Как связать библиотеки языка C? - PullRequest
1 голос
/ 05 июня 2019

Я заинтересован в выполнении функции, написанной на языке C: -

//filename "CLang.c"
#include<stdio.h>
void fun() {
    printf("Hello World");
}

Я хочу назвать это fun() на языке ассемблера, который я написал: - (NASM 64bit)

; filename "MyASM.asm"
section .data

section .bss

section .text
global _start
_start:
    call fun
    mov rax,60  ; exit
    mov rdi,1
    syscall

Я создал объектный файл с помощью этих команд nasm -f elf64 MyAsm.asm и gcc -c CLang.c. Когда я объединяю эти два файла с gcc gcc MyASM.o CLang.o, я получаю сообщение об ошибке

MyASM.o: In function `_start':
MyASM.asm:(.text+0x0): multiple definition of `_start'
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o:(.text+0x0): first defined here
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status

Я не понял, почему в нем говорится как множественное определение _start Я написал только один _start ???
Я понятия не имею, как прикрепить только библиотеки gcc с MyASM.o ???

Ответы [ 2 ]

3 голосов
/ 05 июня 2019

Ошибка, которую вы получаете, состоит в том, что вы определяете _start и потому что вы компилируете и связываете библиотеку C (используя GCC).Библиотека C определяет метку _start, которая инициализирует время выполнения C .Две метки _start являются причиной того, что компоновщик жалуется на переопределение _start.Код запуска C в библиотеке отвечает за передачу управления на main, когда он все правильно инициализировал.

Если вы используете библиотеку C (GLIBC) функционирует прямо или косвенно, чтобы обеспечить правильную инициализацию библиотеки C , связав ее с библиотекой и средой выполнения.По умолчанию это то, что GCC делает для вас (это можно переопределить).

Вы можете определить main как функцию языка ассемблера, например:

extern fun
section .text
global main
main:
    push rbp           ; Pushing a 64-bit register aligns stack back on 16-byte 
                       ; boundary so the call to `fun` has proper 16-byte
                       ; alignment per the AMD64(X86-64) System V ABI.
    call fun
    xor eax, eax       ; RAX=0 (main's return value)
    pop rbp            ; Restore the stack
    ret                ; Return back to C startup code which will exit for us.

Вы должны иметь возможностьиспользуйте существующие команды для сборки с NASM, компиляции с GCC и связи с GCC.

Вы можете найти дополнительную информацию о _start / main и о времени выполнения C ,несколько связанных здесь и информации о опции -nostartfiles в ответах на этот другой вопрос .

Более подробная информация о требованиях к выравниванию стека содержится в ответах на этот Stackoverflow вопрос

0 голосов
/ 05 июня 2019

Как правило, библиотеки создаются из многих исходных файлов библиотек и либо создаются как архивные файлы (libmine.a), которые статически связаны в исполняемые файлы, которые их используют, либо как общие объектные файлы (libmine.so), которые динамически связаны в исполняемые файлы, которые их используют. Для связи в библиотеках этих типов используйте параметры командной строки gcc -L для пути к файлам библиотеки и -l для ссылки в библиотеке (.so или .a):

-L{path to file containing library} -l${library name}

Например, если у меня есть библиотека с именем libmine.so в / home / newhall / lib /, я бы сделал следующее, чтобы связать ее с моей программой:

$ gcc -o myprog myprog.c  -L/home/newhall/lib -lmine

Вам также может понадобиться указать и включить путь, чтобы компилятор мог найти файл заголовка библиотеки: -I / home / newhall / include Если вы создаете свои собственные совместно используемые объектные файлы и не устанавливаете их в / usr / lib, то вам нужно установить переменную среды LD_LIBRARY_PATH, чтобы компоновщик времени выполнения мог их найти и загрузить во время выполнения. Например, если я помещу свои файлы .so в каталог с именем lib в моем домашнем каталоге, я установлю для моей среды LD_LIBRARY_PATH следующее:

# if running bash:
  export LD_LIBRARY_PATH=/home/newhall/lib:$LD_LIBRARY_PATH

  # if running tcsh:
  setenv LD_LIBRARY_PATH /home/newhall/lib:$LD_LIBRARY_PATH
...