Mientras intentaba hacer un programa muy pequeño con NASM y GCC en mi máquina Ubuntu, noté algo extraño.

El siguiente código se compila bien en NASM y GCC de 64 bits:

   global  main
   extern  puts

section .text
   main:
     push    rax
     mov rdi, message
     call puts
     jmp exit
  exit:
    ;return stack memory
    pop rax
    ret
  message:
    db "Hello from NASM!", 0

Pero al intentar compilar el mismo código (solo con los registros cambiados) en NASM y GCC de 32 bits, se producirá un error de segmentación y / o caracteres aleatorios. ¿Por qué está pasando esto? ¿La arquitectura x64 tiene una forma diferente de almacenar memoria en la pila que i386? Si es así, ¿cómo se podría prevenir este comportamiento?

-2
Tatu 17 ene. 2017 a las 17:35
3
Las convenciones de llamadas son diferentes, ¿no es así?
 – 
Kerrek SB
17 ene. 2017 a las 17:37
¿Quizás usar un depurador y averiguar dónde está ocurriendo la falla?
 – 
Tyler Durden
17 ene. 2017 a las 17:39
A menos que hayan cambiado toda la especificación del lenguaje la semana pasada, esto no es C, sino lenguaje ensamblador. ¡No envíes etiquetas de spam! (¡Llamar a las funciones de la biblioteca no cambia esto!)
 – 
too honest for this site
17 ene. 2017 a las 19:07

1 respuesta

La mejor respuesta

En el modo de 32 bits, la mayoría convenciones de llamada (cdecl, stdcall, etc.) esperan que los argumentos se envíen a la pila, no a los registros, a diferencia de Modo de 64 bits, y también, necesitaría ajustar el puntero de la pila después de llamar a puts, por lo que necesitaría hacer algo como:

lea edx, @message
push edx
call puts
add esp, 4

Para que el programa produzca la misma salida en modo de 32 bits. Puede que no tenga la sintaxis NASM correcta, ya que normalmente escribo código ensamblador en MASM y GAS.

3
Govind Parmar 17 ene. 2017 a las 17:45
1
Así que ese era el problema, ¡gracias! Realmente no he terminado con i386 por un tiempo
 – 
Tatu
17 ene. 2017 a las 17:44
1
Realmente no importa lo que requieran la mayoría de las convenciones de llamadas. Esta es una función de biblioteca estándar de C, por lo que utilizará la convención de llamada cdecl, lo que significa que su respuesta es correcta. (Si fuera stdcall, entonces la persona que llama limpiaría la pila, ¡no la persona que llama!)
 – 
Cody Gray
17 ene. 2017 a las 19:01
De acuerdo, seguro, pero estaba tratando de dar una respuesta de caso general: si, por ejemplo, estaba llamando a una función que usaba ms fastcall en lugar de una función C estándar, entonces sería correcto tener el primer argumento en ECX
 – 
Govind Parmar
17 ene. 2017 a las 19:08