Jak połączyć program do montażu gazu, który korzysta z biblioteki standardowej C z ld bez użycia gcc?

Jako ćwiczenie, aby dowiedzieć się dokładniej, jak działają programy w języku c i jaki minimalny poziom zawartości musi istnieć, aby program mógł korzystać z libc, wziąłem na siebie próbę zaprogramowania głównie w x86 assembly przy użyciu gazu i ld.

Jako zabawne małe wyzwanie, z powodzeniem zmontowałem i połączyłem kilka programów powiązanych z różnymi własnymi dynamicznymi bibliotekami, ale nie udało mi się zakodować programu od podstaw, aby używać wywołań funkcji libc bez bezpośrednio przy użyciu gcc.

Rozumiem konwencje wywoływania poszczególnych funkcji biblioteki c i dokładnie sprawdzałem programy skompilowane z gcc poprzez użycie objdump i readelf, ale nie doszedłem do tego, jakie informacje włączyć do pliku montażu gazu i jakie parametry wywołać w ld, aby pomyślnie połączyć się z libc. Ktoś ma w tym jakiś wgląd?

Używam Linuksa, na maszynie x86.

4 answers

Są co najmniej trzy rzeczy, które musisz zrobić, aby z powodzeniem używać libc z dynamicznym łączeniem:

  1. Link /usr/lib/crt1.o, który zawiera _start, który będzie punktem wejścia dla pliku binarnego ELF;
  2. Link /usr/lib/crti.o (przed libc) i /usr/lib/crtn.o (Po), które zapewniają kod inicjalizacji i finalizacji;
  3. Powiedz linkerowi, że binarny użyje linkera dynamicznego, /lib/ld-linux.so.

Na przykład:

$ 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!
$
 22
Author: Matthew Slattery,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-26 23:56:02

Jeśli zdefiniujesz main w zbiorze

Odpowiedź Mateusza świetnie mówi o minimalnych wymaganiach.

Pozwól, że pokażę Ci, jak znaleźć te ścieżki w Twoim systemie. Run:

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

A potem odbierz akta, o których wspominał Matthew.

gcc -v podaje dokładne polecenie linkera, którego używa GCC.

Collect2 to wewnętrzny plik wykonywalny używany przez GCC jako front-end linkera, który ma podobny interfejs do ld.

W Ubuntu 14.04 64-bit (GCC 4.8), skończyło się na:

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

Możesz również potrzebować -lgcc i -lgcc_s. Zobacz także: czy naprawdę potrzebuję libgcc?

Jeśli zdefiniujesz _start w zbiorze

Jeśli zdefiniowałem _start, hello world z glibc działało z just:

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

Nie jestem pewien, czy jest to solidne, tzn. czy inicjalizacje crt można bezpiecznie pominąć w celu wywołania funkcji glibc. Zobacz także: Dlaczego program do montażu działa tylko wtedy, gdy jest połączony z crt1.o crti.o i crtn.o?

 3
Author: Ciro Santilli TRUMP BAN IS BAD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:03

Myślę, że coś takiego powinno działać:

  1. Stwórz prosty program C
  2. Plik gcc-S.c
  3. Edycja pliku.s
  4. Plik gazowy.s
  5. plik ld.o-LC crt1.o-o myprog
 0
Author: Igor Skochinsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-26 19:26:22

Jeśli używasz _start zamiast main (Jak wspomniano w niektórych komentarzach powyżej), musisz również zmienić sposób wyjścia programu, lub dostaniesz błąd seg:

            .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!"

Na 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

Ponadto, jednym z łatwych sposobów, aby dowiedzieć się, co jest dynamicznym linkerem w Twoim systemie, jest skompilowanie małego programu w języku C, a następnie uruchomienie ldd na binarnym:

Test.c:

int main() { return 0; }

Skompiluj i uruchom ldd z wykonywalnym:

$ 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
Author: Andy Turfer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-28 15:09:33