Это программа, которой передается строка в качестве ввода.
Я запутался в коде ассемблера, показанном ниже, в частности в строке 6. Это то, что я понял из моего исследования:
rbp-48
- указатель, который указывает на адрес стека, где хранится argv
.(Сам argv
- это адрес, указывающий на начало массива argv
) - Теперь в регистре rax хранится адрес массива
argv
. - Затем мы добавляем 8 байтов в rax,Это означает, что 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 икод ассемблера corrв соответствии с инструкциями цикла:
#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