linux - El ejecutable compilado de ensamblado en Bash en Ubuntu en Windows no produce salida
assembly x86 (2)
Como ya se señaló en los comentarios de Ross Ridge, no use llamadas de 32 bits de funciones del núcleo cuando compila 64 bits.
Compile para 32 bits o "traduzca" el código en llamadas de sistema de 64 bits. Así es como podría verse:
section .text
global _start ;must be declared for linker (ld)
_start: ;tells linker entry point
mov rdx,len ;message length
mov rsi,msg ;message to write
mov rdi,1 ;file descriptor (stdout)
mov rax,1 ;system call number (sys_write)
syscall ;call kernel
mov rax,60 ;system call number (sys_exit)
mov rdi,0 ;add this to output error code 0(to indicate program terminated without errors)
syscall ;call kernel
section .data
msg db ''Hello, world!'', 0xa ;string to be printed
len equ $ - msg ;length of the string
He estado buscando un tutorial para el ensamblaje, y estoy tratando de ejecutar un programa hello world. Estoy usando Bash en Ubuntu en Windows.
Aquí está la asamblea:
section .text
global _start ;must be declared for linker (ld)
_start: ;tells linker entry point
mov edx,len ;message length
mov ecx,msg ;message to write
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg db ''Hello, world!'', 0xa ;string to be printed
len equ $ - msg ;length of the string
Estoy usando estos comandos para crear el ejecutable:
nasm -f elf64 hello.asm -o hello.o
ld -o hello hello.o -m elf_x86_64
Y lo ejecuto usando:
./hello
Luego, el programa parece ejecutarse sin una falla o error de segmentación, pero no produce ningún resultado.
No puedo entender por qué el código no producirá una salida, pero me pregunto si usar Bash en Ubuntu en Windows tiene algo que ver con eso. ¿Por qué no produce resultados y cómo puedo solucionarlo?
El problema es con Ubuntu para Windows (Subsistema de Windows para Linux).
Solo admite la interfaz
syscall
64 bits y
no
el
mecanismo de llamada al sistema
x86
int 0x80
32 bits
.
Además de no poder usar
int 0x80
(compatibilidad de 32 bits) en binarios de 64 bits, Ubuntu en Windows (WSL)
tampoco admite la ejecución de ejecutables de 32 bits
.
syscall
convertir el uso de
int 0x80
a
syscall
.
No es dificil.
Se utiliza un conjunto diferente de registros para una
syscall
al sistema y los números de llamada del sistema son diferentes de sus contrapartes de 32 bits.
El blog de Ryan Chapman
tiene información sobre la interfaz
syscall
, las llamadas al sistema y sus parámetros.
Sys_write
y
Sys_exit
se definen de esta manera:
%rax System call %rdi %rsi %rdx %r10 %r8 %r9 ---------------------------------------------------------------------------------- 0 sys_read unsigned int fd char *buf size_t count 1 sys_write unsigned int fd const char *buf size_t count 60 sys_exit int error_code
El uso de
syscall
también registra
RCX
y los registros
R11
.
Se consideran volátiles.
No confíe en que tengan el mismo valor después de la
syscall
al
syscall
.
Su código podría modificarse para ser:
section .text
global _start ;must be declared for linker (ld)
_start: ;tells linker entry point
mov edx,len ;message length
mov rsi,msg ;message to write
mov edi,1 ;file descriptor (stdout)
mov eax,edi ;system call number (sys_write)
syscall ;call kernel
xor edi, edi ;Return value = 0
mov eax,60 ;system call number (sys_exit)
syscall ;call kernel
section .data
msg db ''Hello, world!'', 0xa ;string to be printed
len equ $ - msg ;length of the string
Nota: en el código de 64 bits si el registro de
destino
de una instrucción es de 32 bits (como
EAX
,
EBX
,
EDI
,
ESI
, etc.) el
procesador cero extiende el resultado a los 32 bits superiores
del registro de 64 bits.
mov edi,1
tiene el mismo efecto que
mov rdi,1
.
Esta respuesta no es un manual para escribir código de 64 bits, solo se trata de usar la interfaz
syscall
.
Si está interesado en los matices de escribir código que llama a la biblioteca
C
y se ajusta a la ABI de System V de 64 bits, existen tutoriales razonables para comenzar como
el tutorial NASM de Ray Toal
.
Analiza la alineación de la pila, la zona roja, el uso del registro y una descripción básica de la convención de llamadas del Sistema V de 64 bits.