在Linux Windows子系统上的Ubuntu上使用INT 0x80编译的可执行程序集不';不生产
我一直在看汇编教程,我正在尝试运行hello world程序。我在Windows上的Ubuntu上使用Bash 以下是大会:在Linux Windows子系统上的Ubuntu上使用INT 0x80编译的可执行程序集不';不生产,linux,assembly,x86,nasm,windows-subsystem-for-linux,Linux,Assembly,X86,Nasm,Windows Subsystem For Linux,我一直在看汇编教程,我正在尝试运行hello world程序。我在Windows上的Ubuntu上使用Bash 以下是大会: 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 wr
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
我正在使用以下命令创建可执行文件:
nasm -f elf64 hello.asm -o hello.o
ld -o hello hello.o -m elf_x86_64
我使用以下方法运行它:
./hello
程序运行时似乎没有分段错误或错误,但不会产生任何输出
我不明白为什么代码不会产生输出,但我想知道在Windows上的Ubuntu上使用Bash是否与此有关?为什么它不产生输出?我如何修复它?问题在于Ubuntu for Windows(Linux的Windows子系统)。它只支持64位
syscall
接口和系统调用机制
除了不能在64位二进制文件中使用int0x80
(32位兼容性),Windows上的Ubuntu(WSL)也是如此
您需要从使用
int0x80
转换为。这并不难。一组不同的寄存器用于系统调用
,系统调用号与其32位对应的寄存器不同。包含有关syscall
接口、系统调用及其参数的信息<代码>系统写入和<代码>系统退出的定义如下:
同时使用syscall
关闭RCX和R11寄存器。它们被认为是不稳定的。不要指望它们在syscall
之后是相同的值
您的代码可以修改为:
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
注意:在64位代码中,如果指令的目标寄存器是32位(如EAX、EBX、EDI、ESI等),则为64位寄存器的mov edi,1
与mov rdi,1
具有相同的效果
这个答案不是编写64位代码的入门,只是关于使用
syscall
接口。如果您对编写调用C库的代码的细微差别感兴趣,并且符合64位System V ABI,那么有一些合理的教程可以帮助您入门。他讨论了堆栈对齐、红色区域、寄存器使用以及64位SystemV调用约定的基本概述。问题在于Ubuntu for Windows(Linux的Windows子系统)。它只支持64位syscall
接口和系统调用机制
除了不能在64位二进制文件中使用int0x80
(32位兼容性),Windows上的Ubuntu(WSL)也是如此
您需要从使用
int0x80
转换为。这并不难。一组不同的寄存器用于系统调用
,系统调用号与其32位对应的寄存器不同。包含有关syscall
接口、系统调用及其参数的信息<代码>系统写入和<代码>系统退出的定义如下:
同时使用syscall
关闭RCX和R11寄存器。它们被认为是不稳定的。不要指望它们在syscall
之后是相同的值
您的代码可以修改为:
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
注意:在64位代码中,如果指令的目标寄存器是32位(如EAX、EBX、EDI、ESI等),则为64位寄存器的mov edi,1
与mov rdi,1
具有相同的效果
这个答案不是编写64位代码的入门,只是关于使用
syscall
接口。如果您对编写调用C库的代码的细微差别感兴趣,并且符合64位System V ABI,那么有一些合理的教程可以帮助您入门。他讨论了堆栈对齐、红色区域、寄存器使用以及64位SystemV调用约定的基本概述。正如Ross Ridge在评论中指出的,编译64位时不要使用32位内核函数调用
编译32位或将代码“翻译”为64位系统调用。
下面是可能的情况:
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
正如Ross Ridge在评论中指出的,在编译64位时不要使用32位调用内核函数 编译32位或将代码“翻译”为64位系统调用。 下面是可能的情况:
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
在64位可执行文件中使用32位系统调用接口可能与此有关;可能他们也不支持64位可执行文件中的
int0x80
32位ABI。您的代码看起来可以在Linux上运行,在您的64位二进制文件中,.Oh,msg
是否位于不适合32位的地址?这就可以解释了,尽管这不是通常的布局。尝试使用strace./hello
或GDB单步查看eax
中的错误返回值。在64位可执行文件中使用32位系统调用接口可能与此有关;可能他们也不支持64位可执行文件中的int0x80
32位ABI。您的代码看起来可以在Linux上运行,在您的64位二进制文件中,.Oh,msg
是否位于不适合32位的地址?这就可以解释了,尽管这不是通常的布局。尝试使用strace./hello
或GDB单步查看eax
中的错误返回值。我还想警告64b中的不同ABI,在64b中,将参数放入寄存器可能是最容易掌握的部分,但对于刚开始学习汇编的人来说,堆栈对齐和红色区域可能有点棘手。一般来说,我宁愿建议编译为32b二进制文件来回答这样的问题,但在windows中这不是一个选项,因为windows只支持64b linux)我还要警告64b中的不同ABI,在64b中,将参数放入寄存器可能是最容易掌握的部分,