Как связать программу сборки газа, которая использует стандартную библиотеку C, с ld без использования gcc? - PullRequest
13 голосов
/ 26 августа 2010

В качестве упражнения для более точного изучения того, как работают c-программы и какой минимальный уровень контента должен существовать, чтобы программа могла использовать libc, я взял на себя попытку программировать в основном на сборке x86, используя gas и л.д..

В качестве небольшой забавной задачи я успешно собрал и связал несколько программ, связанных с различными самодельными динамическими библиотеками, но мне не удалось написать программу с нуля для использования вызовов функций libc без непосредственного использования gcc.

Я понимаю соглашения о вызовах отдельных функций библиотеки c и тщательно проверял программы, скомпилированные из gcc с использованием objdump и readelf, но нигде не получил информации о том, какую информацию включить в файл сборки газа и что параметры для вызова в ld для успешной ссылки на libc. У кого-нибудь есть понимание этого?

Я использую Linux на компьютере с архитектурой x86.

Ответы [ 4 ]

18 голосов
/ 27 августа 2010

Для успешного использования libc с динамическими ссылками необходимо сделать как минимум три вещи:

  1. Ссылка /usr/lib/crt1.o, которая содержит _start, которая будет точкой входа для двоичного файла ELF;
  2. Ссылка /usr/lib/crti.o (до libc) и /usr/lib/crtn.o (после), которые предоставляют некоторый код инициализации и финализации;
  3. Сообщите компоновщику, что двоичный файл будет использовать динамический компоновщик, /lib/ld-linux.so.

Например:

$ cat hello.s
 .text
 .globl main
main:
 push %ebp
 mov %esp, %ebp
 pushl $hw_str
 call puts
 add $4, %esp
 xor %eax, %eax
 leave
 ret

 .data
hw_str:
 .asciz "Hello world!"

$ as -o hello.o hello.s
$ ld -o hello -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o -lc hello.o /usr/lib/crtn.o
$ ./hello
Hello world!
$
3 голосов

Если вы определили main в сборке

Ответ Мэтью отлично справляется с изложением минимальных требований.

Позвольте мне показать вам, как найтиэти пути в вашей системе.Выполните:

gcc -v hello_world.c |& grep 'collect2' | tr ' ' '\n'

и затем выберите файлы, упомянутые Мэтью.

gcc -v дает точную команду компоновщика, которую использует GCC.

collect2 является внутренним исполняемым GCC, используемым в качестве внешнего интерфейса компоновщика, который имеет интерфейс, аналогичный ld.

В 64-битной Ubuntu 14.04 (GCC 4.8) я получил:

ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 \
  /usr/lib/x86_64-linux-gnu/crt1.o \
  /usr/lib/x86_64-linux-gnu/crti.o \
  -lc hello_world.o \
  /usr/lib/x86_64-linux-gnu/crtn.o

Вам также могут понадобиться -lgcc и -lgcc_s.См. Также: Действительно ли мне нужна libgcc?

Если вы определяете _start в сборке

Если я определил _start,Привет мир из glibc работал только с:

ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc hello_world.o

Я не уверен, что это надежно, то есть, если инициализации crt можно безопасно пропустить для вызова функций glibc.См. Также: Почему программа сборки работает только тогда, когда связаны с crt1.o crti.o и crtn.o?

0 голосов
/ 26 февраля 2019

Если вы используете _start вместо main (как упомянуто в некоторых комментариях выше), вам также придется изменить способ выхода из программы, или вы получите ошибку сегмента:

            .text
            .globl    _start
_start:     
            mov       $hw_str, %rdi
            call      puts
            movl      $0,%ebx   # first argument: exit code.
            movl      $1,%eax   # system call number: sys_exit.
            int       $0x80     # call kernel.

            .data
hw_str:     .asciz "Hello world!"

В Kubuntu 18.04.2 (gcc (Ubuntu 7.3.0-27ubuntu1 ~ 18.04) 7.3.0):

$ as -o hello.o hello.s
$ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o hello hello.o -lc

Кроме того, один простой способ узнать, что такое динамический компоновщикв вашей системе скомпилировать небольшую программу на C, а затем запустить ldd в двоичном файле:

test.c:

int main() { return 0; }

Скомпилировать и запустить ldd для исполняемого файла:

$ gcc -o test test.c
$ ldd test
    linux-vdso.so.1 (0x00007ffd0a182000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff24d8e6000)
    /lib64/ld-linux-x86-64.so.2 (0x00007ff24ded9000)
0 голосов
/ 26 августа 2010

Я думаю, что-то вроде этого должно работать:

  1. сделать простую программу на C
  2. gcc -S file.c
  3. редактировать файл.s
  4. файл газа.s
  5. ld file.o -lc crt1.o -o myprog
...