[bits 32]
global _start
section .data
str_hello db "HelloWorld", 0xa
str_hello_length db $-str_hello
section .text
_start:
mov ebx, 1 ; stdout file descriptor
mov ecx, str_hello ; pointer to string of characters that will be displayed
mov edx, [str_hello_length] ; count outputs Relative addressing
mov eax, 4 ; sys_write
int 0x80 ; linux kernel system call
mov ebx, 0 ; exit status zero
mov eax, 1 ; sys_exit
int 0x80 ; linux kernel system call
这里的基本内容是我需要将 hello 字符串的长度传递给 linux 的 sys_write 系统调用。现在,我很清楚我可以只使用 EQU,它会正常工作,但我真的很想了解这里发生了什么。
所以,基本上当我使用 EQU 时,它会加载值,这很好。
str_hello_length equ $-str_hello
...
...
mov edx, str_hello_length
但是,如果我将此行与 DB 一起使用
str_hello_length db $-str_hello
...
...
mov edx, [str_hello_length] ; of course, without the brackets it'll load the address, which I don't want. I want the value stored at that address
汇编器并没有像我期望的那样在该地址加载值,而是输出 RIP-Relative Addressing,如 gdb 调试器中所示,我只是想知道为什么。
mov 0x6000e5(%rip),%edx # 0xa001a5
现在,我尝试使用 eax 寄存器代替(然后将 eax 移动到 edx),但后来我遇到了另一个问题。我最终得到了 gdb 中指出的分段错误:
movabs 0x4b8c289006000e5,%eax
显然,不同的寄存器产生不同的代码。我想我需要以某种方式截断高 32 位,但我不知道该怎么做。
虽然确实找到了一个“解决方案”,它是这样的:用 str_hello_length 的地址加载 eax,然后加载 eax 指向的地址的内容,一切都是 hunky dory。
mov eax, str_hello_length
mov edx, [eax] ; count
; gdb disassembly
mov $0x6000e5,%eax
mov (%rax),%edx
显然试图从内存地址间接加载一个值会产生不同的代码?我真的不知道。
我只需要帮助理解这些指令的语法和操作,这样我就可以更好地理解为什么要加载有效地址。是的,我想我本可以切换到 EQU 并继续我的快乐之路,但我真的觉得我无法继续,直到我了解 DB 声明和从它的地址加载的情况。