Come collegare un programma di montaggio di gas che utilizza la libreria standard C con ld senza usare gcc?
Domanda
Come esercizio per imparare più precisamente come programmi in C funzionano e quale livello minimo di contenuto deve esistere per un programma di essere in grado di utilizzare libc, ho preso su di me per tentare di programma principalmente in x86 assembly utilizzando gas e ld.
Come un po 'di divertimento sfida, ho assemblato con successo e legato diversi programmi legati a diverse librerie dinamiche self-made, ma io non sono riusciti a essere in grado di codice di un programma da zero per utilizzare chiamate di funzione libc senza direttamente utilizzando gcc.
Capisco le convenzioni di chiamata delle funzioni di libreria C individuale, e hanno programmi compilati fuori gcc attraverso l'uso di objdump e readelf accuratamente ispezionato, ma non ho ottenuto da nessuna parte per quanto riguarda le informazioni da includere in un file di assieme di gas e che cosa parametri di invocare in ld con successo link alla libc. Qualcuno ha qualche intuizione di questo?
Sto lavorando con Linux, su una macchina x86.
Soluzione
Ci sono almeno tre cose che devi fare per utilizzare con successo libc con dinamica di collegamento:
- Collegamento
/usr/lib/crt1.o
, che contiene_start
, che sarà il punto di ingresso per i binari ELF; - Collegamento
/usr/lib/crti.o
(prima libc) e/usr/lib/crtn.o
(dopo), che forniscono un codice di inizializzazione e finalizzazione; - Segnala il linker che il binario utilizzerà il linker dinamico,
/lib/ld-linux.so
.
Ad esempio:
$ 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!
$
Altri suggerimenti
Se si definisce main
in assemblea
La risposta di Matteo fa un grande lavoro di raccontare i requisiti minimi.
mi permetta di mostrare come come trovare quei sentieri nel vostro sistema. Esegui:
gcc -v hello_world.c |& grep 'collect2' | tr ' ' '\n'
e poi raccogliere i file Matteo menzionato.
gcc -v
ti dà gli usi comando GCC linker precisa.
collect2 è gli usi interni GCC eseguibili come linker front-end, che ha un'interfaccia simile a ld
.
In Ubuntu 14.04 a 64 bit (GCC 4.8), ho finito con:
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
Potrebbe anche essere necessario -lgcc
e -lgcc_s
. Vedi anche:? ne ho veramente bisogno libgcc
Se si definisce _start
in assemblea
Se ho definito il _start
, il mondo ciao da glibc lavorato con solo:
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc hello_world.o
Non sono sicuro se questo è robusto, vale a dire se le inizializzazioni crt
possibile saltare in modo sicuro per richiamare le funzioni glibc. Vedi anche: Perché un programma di montaggio funziona solo se collegato con crt1.o crti.o e crtn.o?
Se si utilizza invece di _start
main
(come detto in alcune delle osservazioni di cui sopra), avrete anche bisogno di cambiare il modo in cui il programma si chiude, o si otterrà un guasto 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!"
In 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
Inoltre, un modo semplice per scoprire ciò che il linker dinamico è sul vostro sistema è quello di compilare un piccolo programma C e quindi eseguire ldd
sul binario:
test.c:
int main() { return 0; }
compilare ed eseguire ldd contro eseguibile:
$ 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)
Credo che qualcosa di simile dovrebbe funzionare:
- fare un semplice programma C
- gcc -S file.c
- Modifica file.s
- file.s gas
- ld file.o -lc crt1.o -o mio_prog