[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 相对寻址,如 gdb 调试器中所示,我只是想知道为什么。
mov 0x6000e5(%rip),%edx # 0xa001a5
现在,我尝试改用 eax 寄存器(然后将 eax 移动到 edx),但随后我遇到了不同的问题。我最终遇到了 gdb 中指出的分段错误:
movabs 0x4b8c289006000e5,%eax
显然,不同的寄存器产生不同的代码。我想我需要以某种方式截断高 32 位,但我不知道该怎么做。
虽然确实找到了一个“解决方案”,但它是这样的:
用str_hello_length的地址加载eax,然后加载eax指向的地址的内容,一切都很顺利。
mov eax, str_hello_length
mov edx, [eax] ; count
; gdb disassembly
mov $0x6000e5,%eax
mov (%rax),%edx
显然尝试从内存地址间接加载值会产生不同的代码?我真的不知道。
我只需要帮助理解这些指令的语法和操作,这样我就可以更好地理解为什么如何加载有效地址。是的,我想我可以切换到 EQU 并继续我的快乐之路,但我真的觉得在我了解 DB 声明和从其地址加载的情况之前我无法继续下去。