assembly - 为什么在这种情况下 rax 和 rdi 的工作方式相同?
问题描述
我做了这个代码:
global strlen
; int strlen(const char *string);
strlen:
xor rcx, rcx
retry:
cmp byte [rdi + rcx], 0
je result
inc rcx
jmp retry
result:
mov rax, rcx
ret
这就是我测试它的方式:
#include <stdio.h>
int main(int argc, char **argv)
{
char* bob = argv[1];
printf("%i\n", strlen(bob));
return 0;
}
这是一个有效的 strlen,在这里没问题,但我注意到我可以rdi
将重试块的第一行中的 a 切换为 arax
而不会改变任何内容,我不知道这是否是正常行为。我应该保留哪些价值观?
解决方案
只是运气不好。
GCC 8,没有优化,rax
用作中间位置移动argv[1]
到bob
并将后者移动到的第一个参数strlen
:
push rbp
mov rbp, rsp
sub rsp, 32
mov DWORD PTR [rbp-20], edi ;argc
mov QWORD PTR [rbp-32], rsi ;argv
mov rax, QWORD PTR [rbp-32] ;argv
mov rax, QWORD PTR [rax+8] ;argv[1]
mov QWORD PTR [rbp-8], rax ;bob = argv[1]
mov rax, QWORD PTR [rbp-8]
mov rdi, rax
call strlen ;strlen(bob)
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
leave
ret
这只是运气不好,它不是记录在案的行为,实际上,如果您使用字符串文字,它会失败:
printf("%i\n", strlen("bob"));
mov edi, OFFSET FLAT:.LC1
call strlen ;No RAX here
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
指定如何将参数传递给函数的文档是您的 OS ABI,请在此答案中阅读更多内容。
当优化被禁用时,GCC 会生成大量使用寄存器的“哑”代码,这简化了调试(GCC 引擎和编译的程序)并且基本上模仿了初学者:首先从内存中读取变量并将其放入第一个空闲寄存器(解决了一个问题),然后将其复制到正确的寄存器中(另一个消失了),最后调用。
GCC 刚刚拾取了第一个空闲寄存器,在这个简单的程序中没有寄存器压力并且rax
总是被拾取。
推荐阅读
- c++ - 与 __m256i 和 std::vector 相互转换
- html - HTML & CSS:调整文本上的背景矩形,使其不跨越整个网页
- datatables - 向 DataTables.js 添加加密层
- r - Summarize data within multiple groups of a time series
- c++ - Mutex that works across std implementations
- python - TypeError: 'int' object is not callable on distance
- java - How to enable Spring Bean Validation before persisting but ignore for HTTP request
- jquery - Django using ajax
- python - Pyinstaller 在没有错误消息的情况下卡住
- python - Compress data into smallest amount of text?