使用 write() 在堆栈上输出字符串

Using write() to output string on stack

在 Ubuntu 20 上,在 x86-assembly 中,我试图使用 write 系统调用将字符串 pushed 输出到堆栈上。小端十六进制字节 push 进入堆栈是 "hello world" 在 ASCII 中。我的目标是仅从堆栈中输出字符串。为什么?进一步了解堆栈以及如何通过寄存器将参数传递给 syscalls/functions。

根据我的基本理解,我应该 push 将参数压入堆栈,movesp 寄存器(指向堆栈顶部)按 write的必需参数。

这是我的尝试(没有输出):

; compile: nasm -f elf32 -g test.asm && ld -melf_i386 test.o -o test
section .text
global  _start

_start:
    xor  eax, eax

    push 0xc
    mov  ebx, esp

    push eax
    push 0x00646c72
    push 0x6f77206f
    push 0x6c6c6568

    mov  ecx, esp
    mov  edx, 1
    mov  eax, 4
    int  0x80

    mov  eax, 1
    int  0x80

预期输出:

hello world

如何更正我的代码以显示预期的输出?我做错了什么?

我建议阅读 What are the calling conventions for UNIX & Linux system calls (and user-space functions) on i386 and x86-64。您需要 eax 中的系统调用号和 ebxecxedxesiedi、[=17= 中的参数] 以该顺序。 write 需要三个参数,所以你需要:

  • eax

    中的系统调用号(4)
  • ebx

    中的文件描述符(标准输出为 1)
  • 指向 ecx 中的缓冲区 (esp) 的指针,这是你的权利

  • edx 中要写入的字节数(11,因为没有理由写入空字节)。 (按值,而不是指向长度的指针:write 让您知道通过 eax 中的 return 值实际写入了多少字节,而不是输出参数。)

没有必要在堆栈上放置任何其他东西。内核不会在那里寻找参数,一切都在寄存器中。这与正常的函数调用约定不同。

此外,您可能想在之后调用 exit 系统调用,否则您的程序将 运行 结束其代码并因执行垃圾而崩溃。那是系统调用号 1,它在 ebx 中接受一个参数,这是一个退出代码。

以下作品:

section .text
global  _start

_start:
    push 0x00646c72
    push 0x6f77206f
    push 0x6c6c6568

    mov  ecx, esp
    mov  edx, 11
    mov  ebx, 1
    mov  eax, 4
    int  0x80

    mov  eax, 1
    xor  ebx, ebx
    int  0x80