使用 write() 在堆栈上输出字符串
Using write() to output string on stack
在 Ubuntu 20 上,在 x86-assembly 中,我试图使用 write
系统调用将字符串 push
ed 输出到堆栈上。小端十六进制字节 push
进入堆栈是 "hello world" 在 ASCII 中。我的目标是仅从堆栈中输出字符串。为什么?进一步了解堆栈以及如何通过寄存器将参数传递给 syscalls/functions。
根据我的基本理解,我应该 push
将参数压入堆栈,mov
将 esp
寄存器(指向堆栈顶部)按 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
中的系统调用号和 ebx
、ecx
、edx
、esi
、edi
、[=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
在 Ubuntu 20 上,在 x86-assembly 中,我试图使用 write
系统调用将字符串 push
ed 输出到堆栈上。小端十六进制字节 push
进入堆栈是 "hello world" 在 ASCII 中。我的目标是仅从堆栈中输出字符串。为什么?进一步了解堆栈以及如何通过寄存器将参数传递给 syscalls/functions。
根据我的基本理解,我应该 push
将参数压入堆栈,mov
将 esp
寄存器(指向堆栈顶部)按 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
中的系统调用号和 ebx
、ecx
、edx
、esi
、edi
、[=17= 中的参数] 以该顺序。 write
需要三个参数,所以你需要:
中的系统调用号(4)eax
中的文件描述符(标准输出为 1)ebx
指向
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