2011-01-13 19 views
27

Estoy tratando de usar una función en ensamblado, invocada desde un proyecto C. Se supone que esta función llama a una función libc, digamos printf(), pero sigo recibiendo un error de segmentación.llamando a funciones de ensamblado desde c

En el archivo .c tengo la declaración de la función digamos

int do_shit_in_asm() 

En el archivo asm que tienen

.extern printf 
.section .data 
     printtext: 
       .ascii "test" 
.section .text 
.global do_shit_in_asm 
.type do_shit_in_asm, @function 

do_shit_in_asm: 
    pushl %ebp 
    movl %esp, %ebp 
    push printtext 
    call printf 
    movl %ebp, %esp 
    pop %ebp 
ret 

Cualquier punteros comentario será bienvenido.

as func.asm -o func.o 

gcc prog.c func.o -o prog 
+23

+1 para el nombre de la función –

+33

"Cualquier puntero sería apreciado": int * ptr; – Sapph

+0

@Sapph +1 pero no ayuda :)) –

Respuesta

16

Cambio push printtext a push $printtext.

Como está, está cargando un valor desde la dirección printtext y empujándolo, en lugar de presionar la dirección. Por lo tanto, está pasando 'test' como un número de 32 bits, en lugar de un puntero, y printf está tratando de interpretar eso como una dirección y bloquearse.

9

Una de las mejores maneras de empezar con las funciones del lenguaje ensamblador es escribir una función similar en C y, a continuación, construirlo con el modificador de compilador que genera una lista de montaje (-S en gcc). Luego puede estudiar el resultado de lo que hizo el compilador y modificarlo según sea necesario.

Esto es particularmente útil si llama funciones como printf que usan una convención de llamada diferente (debido a la cantidad variable de argumentos). Llamar a esas funciones puede ser bastante diferente de llamar funciones no varargs.

+1

Muy educativo ... pero también típicamente muy engañoso. El verdadero problema es el ABI, detalles específicos de qué registros deben conservarse, qué significan y cómo interactúan con el C ABI. Inicialmente tomé este camino y luego me di cuenta de que mi ensamblaje no sería mejor de lo que generaría el compilador, ¡que era exactamente lo contrario de lo que estaba tratando de lograr! – bbum

2

Después de esto:

push printtext 
call printf 

que desea buscar:

addl $4, %esp 

una explicación más detallada:

Debido a que usted está utilizando Linux x86 Asumo la convención de llamada requiere que el destinatario de la llamada a la limpieza Los parametros. Debido a que presionó un puntero antes de llamar al printf, su pila está desactivada por 4 después de que se produjera la instrucción ret de esa función.

Actualización:

Sí, está bien, yo estaba acostumbrado a la sintaxis de Intel, así que estaba recibiendo el orden de los argumentos hacia atrás en mi cabeza. En realidad, la falta del addl de nuevo a esp no importa, porque está restaurando esp correctamente cerca de su ret. Mi siguiente conjetura es que la cadena va a ceder a printf que falta un terminador nulo ... Vamos a ver lo que hace ... gas

Actualización 2:

OK, gas nula termina cadenas para usted, así que supongo que mi segunda corazonada fue incorrecta. Parece que encontraste el problema así que el punto es discutible.

+0

error de segmentación –

+0

Me confundí porque estoy acostumbrado a la sintaxis de Intel , no AT & T. En realidad quieres 'addl $ 4,% esp' Espera, déjame echar otro vistazo ... – asveikau

+0

@void - Tal vez puedas verificar en un editor hexadecimal. cadena que pasa a printf obtener nulo terminado? – asveikau

6

el problema era que yo estaba usando

pushl printtext 

vez que

pushl $printtext 

Gracias a todos por su ayuda y lo siento por perder su tiempo: P

+1

Lo tienes justo antes de publicarlo. Felicitaciones por resolver su problema. :-) –