2011-03-04 22 views
10

Soy bastante nuevo en la programación de ensamblaje. Estoy usando la plataforma x86 con GCC (Linux).Pasar un puntero a una función de ensamblaje

que tienen una función que quiero llamar desde C como:

myfunc (unsigned char * s1, unsigned char * s2, int someint); 

La función se llevará a los lugares S1 y S2 de memoria y compararlos, incremente y comparar, etc., haciendo un poco de procesamiento como va. Esto es algo así como memcmp pero estoy haciendo más.

Mi pregunta: si paso un puntero a una función de ensamblaje? Y entonces, ¿cómo digo "dame el valor almacenado en esta dirección de memoria"?

Esto es lo que tengo hasta ahora:

Para obtener el primer argumento de función ("S1") de la pila, hago esto (someaddress es un número entero de 32 bits, y estoy trabajando en un 32 procesador de bits):

movl 8(%esp), %ecx 
movl %ecx, someaddress 

Si pongo somevar en %eax (o %ebx, etc.) y luego printf con %p, veo que su dirección y la dirección del puntero unsigned char "s1" me pasaron son lo mismo Pero sospecho que lo que en realidad he hecho es tomar la dirección de la memoria, convertirla en un entero, y luego poner ese entero en alguna dirección.

Por ejemplo, si yo hago esto:

movl pos1, %eax 
movl pos2, %ebx 
cmp (%eax),(%ebx) 

recibo "Error: demasiadas referencias a memoria para` cmp '". No estoy del todo seguro de lo que eso significa, excepto "te equivocaste" ;-)

Entonces ...

  • cómo pasar un puntero y mantenerlo como un puntero?
  • cómo usar el valor de dicho puntero en el ensamblaje? (Por ejemplo, como *ptr en C)

¿Deseo consultar el operando LEA?

Estoy utilizando la "Programación de montaje profesional" de Richard Blum como mi guía, pero Blum no parece cubrir este caso.

actualización

Muchas gracias por su respuesta aprendida!

Desafortunadamente, todavía no puedo quitar la referencia.

Aquí hay un ejemplo simplificado. La función de ensamblaje toma un puntero y debe repetirlo.En su lugar me sale:

first_ptr points to 81 (should be 81) <-- from C program 
the value is -1543299247 <-- printf called from within assembler 
the value is -6028513 <-- printf called from within assembler 
my function returned -6028513 <-- return value printed from C program 

Programa C: Programa

#include <stdio.h> 
#include <string.h> 

int main (void) { 
     unsigned char first; 
     unsigned char * first_ptr; 

     first = 'Q'; 
     first_ptr = &first; 

     printf ("first_ptr points to %i (should be 81)\n",*first_ptr); 

     printf ("my function returned %i\n", myfunc(first_ptr)); 
     return 0; 
} 

Asamblea:

.section .data 

msg: 
    .asciz "the value is %i\n" 

.section .bss 
.lcomm str, 8 

.section .text 
.type myfunc, @function 
.globl myfunc 
myfunc: 

    # save stack 
    pushl %ebp 
    movl %esp, %ebp 

    # save string arg from stack to "str" 
    movl 8(%esp), %ecx 
    movl %ecx, str 

    # let's try printing the ecx dereference 

    pushl (%ecx) 
    pushl $msg 
    call printf 

    # put the value of str on the stack 
    # and call printf 

    pushl (str) 
    pushl $msg 
    call printf 

    # now return the character at pos1 
    movl (str), %eax 

    # restore the stack 
    movl %ebp, %esp 
    popl %ebp 

    ret 
+0

Problemas con su código actualizado: Para imprimir el valor, está empujando 32 bits mientras que la variable tiene solo 8 bits. Puede extenderlo a 32 bits (que es lo que hace C) o cambiar la cadena de formato. Tenga en cuenta que los 8 bits bajos de -1543299247 de hecho se evalúan a 81, como se esperaba. Para la segunda impresión y la devolución: Está intentando utilizar la doble desreferencia escribiendo (str) y no existe tal cosa en x86. El ensamblador debería arrojar un error para eso, si me preguntas, pero en lugar de eso cae silenciosamente entre paréntesis. – Jester

Respuesta

8

Al menos uno de los operandos a cmp tiene que ser un registro. Si está intentando comparar el contenido de dos ubicaciones de memoria, deberá colocar una de ellas en un registro. ¿Cómo se puede obtener en un registro? Bueno, ya has hecho eso con tu código de ejemplo. Esta línea:

movl 8(%esp), %ecx 

Toma los 4 bytes en% esp + 8 y los pone en% ecx. En un psuedocode tipo C:

ecx = *(esp + 8); 

Espero que tenga sentido. Puede hacer operaciones similares para sacar los punteros de la pila y colocarlos en los registros, y luego eliminarlos, comparar los valores desreferenciados, y así sucesivamente. ¡Avíseme si tiene más preguntas!

Editar - sus preguntas estallado:

  1. que ya está haciendo eso, y su instrucción movl 8(%esp), %ecx, o algo por el estilo van a hacer todo lo necesario.

  2. how to use the value of said pointer in assembly? (e.g., like *ptr in C)

    Es necesario utilizar el () nuevo - para cargar el primer byte del puntero en %ecx de su instrucción anterior, por ejemplo:

    movb (%ecx), %edx 
    

    En el pseudocódigo C-como similar a como lo he usado anteriormente, esta instrucción es:

    edx = *(unsigned char *)ecx; 
    
  3. Do I want to look at the LEA operand?

    Probablemente no, basado en la descripción de su problema que ha proporcionado. Sin embargo, siempre es posible. lea funciona algo así como el operador & en C.A modo de ejemplo, esta instrucción:

    lea 12(%ecx), %edx 
    

    se puede traducir en nuestro pseudocódigo como:

    edx = &(*(ecx + 12)) 
    

    o más simplemente:

    edx = ecx + 12 
    

    Este ejemplo es un poco tonto, ya que' re utilizando un modo de direccionamiento relativamente sencillo, pero ¿qué tal algo así:

    lea 1(%edx,%ecx,4), %eax 
    

    que significa:

    eax = &(edx[ecx * 4] + 1) 
    

A menudo la solución más fácil a este tipo de problemas es escribir su rutina en C, a continuación, compilar y desmontar los resultados.

Edición 2:

Su programa de ejemplo parece casi correcto, pero usted está tratando de punteros en la memoria dereference - conseguir esos registros punteros en primera y usted debe estar bien.

Cuestiones relacionadas