一尘不染

Windows上的Ubuntu上的Bash上的汇编编译可执行文件不产生输出

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 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是否与此有关?为什么它不产生输出,我该如何解决?


阅读 294

收藏
2020-06-02

共1个答案

一尘不染

问题出在Windows的Ubuntu(Linux的Windows子系统)上。它仅支持64位syscall接口, int 0x80支持32位x86系统调用机制。

除了无法int 0x80在64位二进制文​​件中使用(32位兼容性)之外,Windows上的Ubuntu(WSL)也不支持运行32位可执行文件


您需要从使用转换int 0x80syscall。不难
a使用一组不同的寄存器,syscall并且系统调用号与其32位对应号不同。Ryan
Chapman的博客中
包含有关syscall界面,系统调用及其参数的信息。Sys_writeSys_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也则会覆盖 RCXR11 寄存器。它们被认为是易变的。结束后不要依赖于它们具有相同的值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位(例如 EAXEBXEDIESI
等),则处理器零会将结果扩展到
64位寄存器的高32位。mov edi,1具有与相同的效果mov rdi,1


这个答案不是编写64位代码的入门,仅是关于使用syscall接口的。如果您对编写调用 C 库并符合64位System V
ABI的代码的细微差别感兴趣,那么可以使用Ray
Toal的NASM教程之
类的合理教程来入门。他讨论了堆栈对齐,红色区域,寄存器使用情况以及64位System
V调用约定的基本概述。

2020-06-02