Функции стека сборки 3

#assembly #x86

#сборка #x86

Вопрос:

 aduna2:

.LFB0:
.cfi_startproc
    push    ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
    mov ebp, esp
.cfi_def_cfa_register 5
    sub esp, 16
    mov DWORD PTR [ebp-4], 10
    mov eax, DWORD PTR [ebp 12]
    mov edx, DWORD PTR [ebp 8]
    add edx, eax
    mov eax, DWORD PTR [ebp 16]
    add edx, eax
    mov eax, DWORD PTR [ebp-4]
    add eax, edx
    leave

aduna:

.LFB1:
.cfi_startproc
    push    ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
    mov ebp, esp
.cfi_def_cfa_register 5
    sub esp, 28
    mov DWORD PTR [ebp-4], 7
    mov eax, DWORD PTR [ebp-4]
    mov DWORD PTR [esp 8], eax
    mov eax, DWORD PTR [ebp 12]
    mov DWORD PTR [esp 4], eax
    mov eax, DWORD PTR [ebp 8]
    mov DWORD PTR [esp], eax
    call    aduna2
    leave

main:

.LFB2:
.cfi_startproc
    push    ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
    mov ebp, esp
.cfi_def_cfa_register 5
    and esp, -16
    sub esp, 16
    mov DWORD PTR [esp 4], 6
    mov DWORD PTR [esp], 5
    call    aduna
    mov DWORD PTR [esp 4], eax
    mov DWORD PTR [esp], OFFSET FLAT:.LC0
    call    printf
    leave
  

В этом коде у меня есть следующие вопросы: В основном я не могу понять, куда идет esp при замене esp 16 относительно ebp. Эти вопросы у меня есть в «adunare» и «adunare2». Я не могу понять, где это будет относительно ebp.Я не могу понять, как нарисовать стек для этой программы, потому что все мои стеки застряли, когда в «adunare2» я получаю ebp 8, ebp 12, ebp 16.Было бы полезно показать мне один, потому что я не понимаю, что происходит. И при каждом вызове туда вставляется обратный адрес? Если да в «adunare2», как вы можете получить указанные параметры, используя 8, 12, 16?

Вот код c:

 #include<stdio.h>

int aduna2(int a,int b,int c) 
{
    int d=10;
    return a b c d;
}

int aduna(int a,int b)
{
    int c=7;
    return aduna2(a,b,c);
}

int main()
{
    printf("%dn",aduna(5,6));
}
  

Комментарии:

1. Эта разборка выглядит неполной. (Я бы ожидал ret после leave ). Как вы это получили? Разве это не какой-то «умный» вывод дизассемблера? Используйте либо список компилятора, либо обычную разборку.

Ответ №1:

Даже из неполной разборки я думаю, что могу ответить на вопрос «что делает main со стеком перед aduna»:

 main:
    ; store old ebp value into stack (to restore it before return)
    push  ebp
    mov   ebp, esp   ; copy current value of esp to ebp
  

На данный момент как esp, так и ebp имеют одинаковое значение, указывая на текущую вершину стека, скажем, это 0x0054 , тогда (стековая) память выглядит следующим образом:

 address | value
-----------------
0x0050  | ????
0x0054  | old_ebp           <- esp/ebp pointing here
0x0058  | return address to "main" caller
0x005C  | whatever was already in stack before calling main
  

Затем код продолжает подготавливать параметры для функции «aduna»:

     and   esp, -16     ; -16 = 0xFFFFFFF0 -> makes esp 16B aligned
       ; esp here is 0x0050
    sub   esp, 16      ; make room at top of stack for 16B, esp = 0x0040
       ; store the arguments into the stack
    mov   DWORD PTR [esp 4], 6   ; at 0x0044 goes value 6
    mov   DWORD PTR [esp], 5     ; at 0x0040 goes value 5
    call  aduna                  ; call aduna
  

Теперь сразу после ввода aduna ebp / esp и стековая память выглядят следующим образом:

 ebp = still 0x0054, nothing did modify it
esp = 0x003C (call did pust return address at top of stack)

address | value
-----------------
0x0038  | ????
0x003C  | return address to instruction after "call aduna" <- esp
0x0040  | 5
0x0044  | 6
0x0048  | ????
0x004C  | ????
0x0050  | ????
0x0054  | old_ebp           <- ebp pointing here
0x0058  | return address to "main" caller
0x005C  | whatever was already in stack before calling main
  

И aduna начните с кода пролога push ebp mov ebp, esp , поэтому верхняя часть стека немного изменится:

 address | value
-----------------
0x0038  | 0x0054  <- both esp and ebp pointing here (= 0x0038)
0x003C  | return address to instruction after "call aduna"
0x0040  | 5
0x0044  | 6
  

Таким образом, mov eax, DWORD PTR [ebp 12] будет получен адрес 0x0044 (0x38 0x0C = 0x44), там хранится 6. ebp 8 указывает на значение 5. Остальные esp / ebp комбинации в aduna пунктах ниже этого, в локальные переменные (которые находятся в «стековой» части памяти), которые я не собираюсь описывать, как только вы пойметеэта начальная часть, вы должны быть в состоянии расшифровать и остальную ее часть.

Для leave проверки руководства по набору инструкций (оно меняет оба esp и ebp ). И отсутствие ret тоже важно, esp оно также меняется.