#cpp #ассемблер #указатели
void foo(int a)
{
a = a + a;
}
void foo(int *a)
{
*a = *a + *a;
}
ASM:
foo(int):
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
sal DWORD PTR [rbp-4]
nop
pop rbp
ret
foo(int*):
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
mov rax, QWORD PTR [rbp-8]
mov eax, DWORD PTR [rax]
lea edx, [rax+rax]
mov rax, QWORD PTR [rbp-8]
mov DWORD PTR [rax], edx
nop
pop rbp
ret
Как устроены указатели на уровне ассемблера ?
Ответы
Ответ 1
У процессора, т.е. в языке ассемблера, фактически все операции в оперативной памяти происходят "по указателю". Обратиться к ячейке памяти (переменной) можно только по ее конкретному адресу. Адрес при этом должен быть доступен инструкции непосредственно, т.е. находиться в самой инструкции, в регистре или вычисляться из регистров и констант. Указатель в языке C это переменная в памяти, содержащая тот самый адрес, по которому надо обращаться к данным. В приведенных вами примерах параметр функции передается через регистр. В первом случае передано само 32 битное значение, поэтому оно в регистре edi. Во втором - это 64 битный адрес, т.е. указатель (он в 64 битном регистре rdi). В этих примерах так же много лишнего кода (видимо выключена оптимизация). В первом примере значение из регистра переноситься в локальную область стека (в переменную a) и она умножается на 2. Достаточно было бы sal edi. Хотя конечно одного ret было бы более чем достаточно, потому что код фактически ничего не делает, он меняет свою локальную переменную, которую никуда не возвращает. Второй пример в идеале можно сократить до: foo(int*): ; В rdi указатель на 32 битную переменную. mov eax, DWORD PTR [rdi] ; Помещаем в eax значение, находящееся по адресу (указателю) rdi sal eax ; сдвиг eax влево на 1 бит ( eax*=2 ) mov DWORD PTR [rdi], eax ; Помещаем eax обратно по адресу из rdi ret Обратите внимание, что работа с локальными переменными, находящимися в стеке шла точно так же, в rbp находится указатель на текущий кадр стека, доступ к переменным осуществляется по этому адресу с некоторым смещением ([rbp+8]). Фактически rbp это точно такой же указатель, по которому происходит работа. Но язык высокого уровня, для удобства программиста отличает просто переменные и указатели
Комментариев нет:
Отправить комментарий