Понимание C против его сборки аналога - PullRequest
0 голосов
/ 10 октября 2018

Скажем, нам дана функция:

    int exchange(int*xp, int y)
    {
    x = *xp; 
    *xp = y; 
    return x;

    }

Итак, книга, которую я читаю, объясняет, что xp хранится со смещением 8 и 12 относительно регистра адресов% ebp.Что я не понимаю, так это то, почему они хранятся в виде любого вида блоков 8 и 12, более того: что является смещением в этом контексте?Наконец, как подходят 8 и 12, когда регистр принимает движение в единицах 1, 2 и 4 байта соответственно?

Код ассемблера:

xp at %ebp+8, y at%ebp+12 
1 movl 8(%ebp), %edx (Get xp By copying to %eax below, x becomes the return value)

2 movl (%edx), %eax (Get x at xp) 

3 movl 12(%ebp), %ecx (Get y) 

4 movl %ecx, (%edx) (Store y at xp)

Я думаю, что ответ таков: так, при рассмотрении реестров, было обычным явлением видеть что-то вроде реестра% rdi, содержащее значение 0x1004, которое являетсяадрес и 0x1004 находится в адресе, который содержит значение 0xAA.

Конечно, это гипотетический пример, который не совпадает с реестрами, перечисленными в книге.Каждый реестр является 16-32-разрядным, и первые четыре можно использовать для свободного хранения целых чисел.Делает ли смещение на 8 сходство с 0x1000 + 8?Опять же, я не совсем уверен, для чего смещение в этом сценарии, когда мы храним новые юниты в пустом пространстве.

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

Из-за того, как структурирован стек вызовов при использовании объявления C .

Сначала вызывающий абонент push 4-байтовый y, затем 4-байтовый xp (этот порядок важен, поэтому C может поддерживать Variadic Functions ), тогда call для вашей функции будет неявно push адрес возврата, который также является 4-байтовым (это 32-битная программа).

Первое, что делает ваша функция, это push состояние ebp, которое необходимо будет восстановить позже, чтобы вызывающий мог продолжить работу должным образом, а затем скопировать текущее состояние esp(указатель стека) на ebp.В сумме:

push %ebp
movl %esp, %ebp

Это также известно как пролог функции .

Когда все это сделано, вы наконец готовы фактически выполнить код, который вы написали, вна этом этапе стек выглядит примерно так:

%ebp- ? = address of your local variables (which in this example you don't have)
%ebp+ 0 = address of the saved state of previous ebp
%ebp+ 4 = ret address
%ebp+ 8 = address where is stored the value of xp
%ebp+12 = address where is stored the value of y
%ebp+16 = out of bonds, this memory space belongs to the caller

Когда ваша функция будет выполнена, она обернет ее, установив esp обратно на ebp, затем pop оригинал ebp и ret.

movl %ebp, %esp
pop %ebp
ret

ret - это, по сути, ярлык для pop указателя из стека и jmp к нему.

Редактировать: Исправлен порядок параметров для сборки AT & T

0 голосов
/ 10 октября 2018

Посмотрите на нормальную запись функции в ассемблере:

    push ebp
    mov ebp, esp
    sub esp, <size of local variables>

Итак, ebp+4 содержит предыдущее значение ebp.До того, как старый ebp был адресом возврата, на ebp+8.Перед этим находятся параметры функции в обратном порядке, поэтому первый параметр имеет значение ebp+12, а второй - ebp+8.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...