这是一个传递String作为输入的程序 .
我对下面显示的汇编代码感到困惑,特别是第6行 . 这是我从我的研究中理解的:
-
rbp-48
是一个指向存储argv
的堆栈地址的指针 . (argv
本身,是指向argv
数组开头的地址) -
现在rax寄存器存储
argv
数组地址 . -
然后我们向rax添加8个字节 . 这意味着rax现在指向
argv[1]
的地址 . (据我所知,argv[1]
中存在另一个指向字符串的地址) . -
然后我们访问存储在argv [1]中的值并将其存储在rdx寄存器中 . 这意味着,rdx现在指向字符串开头的地址 .
-
然后我们将[rbp-24] = i计数器变量移动到eax寄存器 .
-
然后我们有一个动作cdqe,我认为它不相关 .
现在是我感到困惑:如果我想访问 argv[1]
中的第一个字符并将其存储在eax寄存器中,我希望汇编程序可以执行以下操作:
mov eax, BYTE PTR [rdx]
如果我需要访问存储在argv [1]中的第二个字符并将其存储在eax寄存器中,我希望汇编程序可以执行以下操作:
mov eax, BYTE PTR [rdx+1]
但相反,我看到编译器执行以下操作:
add rax, rdx
- 在字符串开头的内存中添加地址,内存中的地址是指向字符串开头的地址,并将此结果保存在rax中 .
我无法理解这条指令如何使rax指向argv [1]中的任何字符 .
下面是与循环指令对应的C代码和汇编代码:
#include <string.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
int sum = 0;
for(int i = 0; i < strlen(argv[1]); i ++){
sum += (int)argv[1][i];
}
return 0;
}
部件
mov rax, QWORD PTR [rbp-48]
add rax, 8
mov rdx, QWORD PTR [rax]
mov eax, DWORD PTR [rbp-24]
cdqe
add rax, rdx
movzx eax, BYTE PTR [rax]
movsx eax, al
add DWORD PTR [rbp-20], eax
add DWORD PTR [rbp-24], 1
1 回答
哦,我终于弄明白了你的困惑 . 在有问题的指令中,rax不再包含argv;它重新加载了i的值 . 编译器使用
add
指令而不是索引寻址模式 .eax是rax的低32位 . 加载eax时,该值将零扩展为64位 .
然后
cdqe
将EAX签名扩展为RAX,因为i
是一个带符号的32位整数,用于索引指针 . 编译器可以通过加载简化movsx rax, dword ptr [rbp-24]
.