Почему ESP указывает на [esp + 0xc]? - PullRequest
0 голосов
/ 01 июля 2019

Я хотел бы изучить некоторую сборку, и теперь у меня есть вопрос, где ESP смещает инициализированное целое число во время вызова функции основной функции.

C-код:

#include<stdio.h>


int main() {
    int hallo = 5;
}

Когда я компилирую этот файл с помощью GCC и декомпилирую его с помощью команды objdump -M intel -D a.exe | grep -A20 main.

Тогда это выглядит так:

00401460 <_main>:
  401460:       55                      push   ebp
  401461:       89 e5                   mov    ebp,esp
  401463:       83 e4 f0                and    esp,0xfffffff0
  401466:       83 ec 10                sub    esp,0x10
  401469:       e8 42 05 00 00          call   4019b0 <___main>
  40146e:       c7 44 24 0c 05 00 00    mov    DWORD PTR [esp+0xc],0x5
  401475:       00
  401476:       b8 00 00 00 00          mov    eax,0x0
  40147b:       c9                      leave
  40147c:       c3                      ret
  40147d:       90                      nop
  40147e:       90                      nop
  40147f:       90                      nop

00401480 <__setargv>:
  401480:       55                      push   ebp
  401481:       89 e5                   mov    ebp,esp
  401483:       57                      push   edi
  401484:       56                      push   esi
  401485:       53                      push   ebx
--
004019b0 <___main>:
  4019b0:       a1 28 70 40 00          mov    eax,ds:0x407028
  4019b5:       85 c0                   test   eax,eax
  4019b7:       74 07                   je     4019c0 <___main+0x10>
  4019b9:       f3 c3                   repz ret
  4019bb:       90                      nop
  4019bc:       8d 74 26 00             lea    esi,[esi+eiz*1+0x0]
  4019c0:       c7 05 28 70 40 00 01    mov    DWORD PTR ds:0x407028,0x1
  4019c7:       00 00 00
  4019ca:       eb 94                   jmp    401960 <___do_global_ctors>
  4019cc:       90                      nop
  4019cd:       90                      nop
  4019ce:       90                      nop
  4019cf:       90                      nop

004019d0 <.text>:
  4019d0:       83 ec 1c                sub    esp,0x1c
  4019d3:       8b 44 24 24             mov    eax,DWORD PTR [esp+0x24]
  4019d7:       83 f8 03                cmp    eax,0x3
  4019da:       74 14                   je     4019f0 <.text+0x20>
  4019dc:       85 c0                   test   eax,eax

Я ожидаю, что последняя команда сборки будет mov DWORD PTR [esp+0xF],0x5, поскольку стек растет сверху вниз и из-за Little Endian, ESP должен быть расположен на [esp+0xF], чтобы заполнить следующие 4 байта (целое число) до позиции [esp+0xc].

1 Ответ

3 голосов
/ 01 июля 2019

Нет, хранилище dword для [esp+0xF] записывает 4 байта в [esp + 0x0f .. 0x12], что даже не выровнено по dword.

Если вас смущает Отношение между порядком байтов и стеком- направление роста и старые ответы там, это понятно;они были совершенно неверными, поэтому я отправил правильный.

Адрес меча всегда является самым низким адресом любого из его компонентных байтов. (Это относится к старшему и младшему порядковому порядку байтов)систем).

Резервирование 16 байтов и сохранение в [esp+0xc] сохраняет до 4 байтов с наибольшим адресом из этих 16.

Меч в [esp+0xc] есть (в порядке отОт LSB к MSB) байты по адресам ESP +0xc, +0xd, +0xe и +0xf.

Для (гипотетического) старшего байта x86 это будут те же байты,но этот порядок будет MSB для LSB.Адрес меча все равно будет [esp+0xc].

. Ничто из этого не имеет никакого отношения к push, делающему esp-=4 вместо esp+=4.Системы с растущими вверх стеками по-прежнему используют адрес младшего байта в слове / слове в качестве адреса этого многобайтового целого числа.Как и в C, адрес массива или структуры является адресом первого элемента.На самом деле это , почему C-адреса работают именно так.


Так как стек растет вниз, есть некоторый смысл, что gcc выберет, чтобы поместить туда локальный, прямо под сохраненным EBPзначение и оставьте оставшуюся часть пространства неиспользованной как заполнитель для выравнивания стека перед call (для вспомогательной функции CRT ___main).

Даже если для 32-разрядного ABI Windows не требуется 16-байтовое выравнивание стека, gcc выбирает делать это в любом случае (по умолчанию -mpreferred-stack-boundary=4: 2 ^ 4 = 16)


И кстати, очевидно, весь этот шум исчезнет, ​​если вы компилируете с включенной оптимизацией.Тогда основной может просто ret.Или, возможно, все еще должен позвонить ___main, но может оптимизировать местный.

Вы можете уменьшить шум, но все же сделать GCC init локальным, сделав его volatile и скомпилировав с -O3.Или передайте его адрес другой не встроенной функции.


Почему ESP указывает на [esp + 0xc]?

А?Это даже не имеет смысла.ESP указывает на [esp].Вы на самом деле спрашиваете, почему GCC решил использовать режим адресации [esp+0xc], а не какое-либо другое смещение.

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