2011-12-31 15 views
9

Tengo problemas para vincular 2 archivos de objetos, uno de los cuales se generó a partir de un archivo de origen de lenguaje de ensamblado y otro que se generó a partir de un archivo de origen de C.¿Cómo vincular un archivo de objeto C con un archivo de objeto de lenguaje ensamblador?

C código fuente:

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

código fuente Asamblea:

#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 

Cuando compilar y ejecutar el uso de 'gcc' como esto:

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

consigo 5, que es correcto. Sin embargo cuando compilo/montar por separado y luego enlazar con 'ld' así:

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 

consigo un fallo de segmentación. ¿Qué está causando esto? ¿No estoy siguiendo la convención de llamadas C al 100% correctamente?

Respuesta

11

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

no hacen eso. Hacer esto en su lugar:

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

(probablemente no debería llamar a su exectuable prueba test, ya que puede entrar en conflicto con la /bin/test, estándar en la mayoría de los sistemas UNIX.)

Explicación: binarios UNIX hacen no general comience a ejecutar en main. Empiezan a ejecutar en una función llamada _start, que viene de crt1.o o similar ("C Inicio en tiempo de ejecución"). Ese archivo es parte de libc, y arregla varias inicializaciones necesarias para el correcto inicio de su aplicación.

Su programa realmente no requiere nada de libc, razón por la que fueron capaces de enlazar con ld.

Sin embargo, considere lo que ocurre después de que su main regresa. Normalmente, se ejecutará el código en crt1.o (equivalente a) exit(main(argc, argv));. Como ha vinculado sin crt1.o, no hay nadie para hacer esa final exit, por lo que el código vuelve a ... ubicación indefinida y se bloquea rápidamente.

4

También necesita vincular el crt1.o (puede tener un nombre diferente, contiene el código necesario hasta que se pueda llamar al main) y las bibliotecas necesarias. GCC también necesita generalmente vincularse al libgcc.so que contiene las funciones auxiliares necesarias (por ejemplo, al hacer cálculos de 64 bits en un sistema de 32 bits) más otras bibliotecas del sistema. Por ejemplo, en mi Mac, también necesita vincularse al libSystem, que también contiene las funciones C habituales, como printf. En Linux, generalmente es libc.

Tenga en cuenta que el programa no se puede iniciar directamente con main (como usted está tratando de hacer con la ld .. -e main), el punto de entrada tiene que configurar algunas cosas antes de llamar a la función C main. Eso es lo que está haciendo el crt1.o anteriormente mencionado. Supongo que la falla de segmentación es el resultado de esta configuración faltante.

Para ver lo que está haciendo exactamente GCC en su sistema, llame a:

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