2011-12-31 6 views
9

Ho problemi a collegare 2 file oggetto uno dei quali è stato generato da un file sorgente linguaggio assembly e un altro generato da un file sorgente C.Come collegare un file oggetto C con un file oggetto Assembly Language?

C codice sorgente:

//main2.c 
extern int strlength(char *); 
int main(){ 
    char * test = "hello"; 
    int num = strlength(test); 
    return num; 
} 

codice sorgente Assembly:

#strlength.s 
.include "Linux32.s" 

.section .text 
.globl strlength 
.type strlength, @function 
strlength: 
pushl %ebp 
movl %esp, %ebp 
movl $0, %ecx 
movl 8(%ebp), %edx 
read_next_byte: 
movb (%edx), %al 
cmpb $END_OF_FILE, %al 
jle end 
incl %edx 
incl %ecx 
jmp read_next_byte 
end: 
movl %ecx, %eax 
popl %ebp 
ret 

Quando ho compilare ed eseguire usando 'gcc' in questo modo:

gcc main2.c strlength.s -m32 -o test 
./test 
echo $? 

ottengo 5 che è corretta. Tuttavia quando compilo/montare separatamente e poi creare un collegamento con 'ld' come questo:

as strlength.s --32 -o strlength.o 
cc main2.c -m32 -o main2.o 
ld -melf_i386 -e main main2.o strlength.o -o test 
./test 

ottengo un segmentation fault. Che cosa sta causando questo? Non sto seguendo correttamente la convenzione di chiamata C al 100%?

risposta

11

ld -melf_i386 -e main main2.o strlength.o -o test

non lo faccio. Fate questo invece:

gcc -m32 main2.o strlength.o -o test 

(si dovrebbe probabilmente non chiamare il test exectuable test, come si può entrare in conflitto con la /bin/test, di serie sulla maggior parte dei sistemi UNIX.)

Spiegazione: binari UNIX fanno non generale iniziare l'esecuzione a main. Inizia l'esecuzione in una funzione denominata _start, che viene da crt1.o o simile ("Avvio in runtime C"). Il file fa parte di libc e organizza varie inizializzazioni, necessarie per l'avvio corretto dell'applicazione.

Il vostro programma in realtà non richiede nulla da libc, che è il motivo per cui sono stati in grado di collegarlo con ld.

Tuttavia, considerare cosa succede dopo i ritorni main. Normalmente, il codice in crt1.o verrà eseguito (equivalente a) exit(main(argc, argv));. Dal momento che hai effettuato il collegamento senza lo crt1.o, non c'è nessuno che faccia per te l'ultimo exit, quindi il codice ritorna in ... posizione non definita e si blocca immediatamente.

4

È inoltre necessario collegare crt1.o (potrebbe avere un nome diverso, contiene il codice necessario fino a main può essere chiamato) e le librerie necessarie. GCC di solito ha anche bisogno di collegarsi a libgcc.so che contiene le necessarie funzioni di supporto (ad esempio, quando si eseguono calcoli a 64 bit su un sistema a 32 bit) più altre librerie di sistema. Ad esempio, sul mio Mac, deve anche collegarsi a libSystem che contiene anche le solite funzioni C come printf. Su Linux, di solito è libc.

Nota che il programma non può iniziare direttamente con main (come si sta cercando di fare con con ld .. -e main), il punto di ingresso deve impostare un paio di cose prima di chiamare la funzione C main. Questo è ciò che sta facendo il già citato crt1.o. Immagino che l'errore di segmentazione sia il risultato di questa installazione mancante.

Per vedere che cosa sta esattamente facendo GCC sul sistema, chiamano:

gcc main2.c strlength.s -m32 -o test -v