![](/img/trans.png)
[英]Is int 0x80 is the only interrupt number used in linux assembly programming?
[英]Assembly compiled executable using INT 0x80 on Ubuntu on Windows Subsystem for Linux doesn't produce output
我一直在看汇编教程,我正在尝试运行一个 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 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 是否与它有关? 为什么它不产生输出,我该如何解决?
问题在于 Windows 版 Ubuntu(Linux 版 Windows 子系统)。 它仅支持 64 位syscall
接口而不支持32 位 x86 int 0x80
系统调用机制。
除了无法在 64 位二进制文件中使用int 0x80
(32 位兼容性)之外,Windows 上的 Ubuntu (WSL) 也不支持运行 32 位可执行文件。
您需要从使用int 0x80
转换为syscall
。 这并不难。 一组不同的寄存器被用于syscall
和系统调用编号是从他们的32位对应不同。 Ryan Chapman 的博客提供了有关syscall
接口、系统调用及其参数的信息。 Sys_write
和Sys_exit
是这样定义的:
%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
使用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 位寄存器的高 32位。 mov edi,1
与mov rdi,1
具有相同的效果。
这个答案不是编写 64 位代码的入门,只是关于使用syscall
接口。 如果您对编写调用C库并符合 64 位 System V ABI 的代码的细微差别感兴趣,那么有一些合理的教程可以帮助您入门,例如Ray Toal 的 NASM 教程。 他讨论了堆栈对齐、红色区域、寄存器使用以及 64 位 System V 调用约定的基本概述。
正如 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.