что это между локальным var и EBP в стеке? - PullRequest
1 голос
/ 12 ноября 2010

Для этого простого кода:

void main(){
  char buf[12];
  buf[11]='\xff';
  puts(buf);
}

Я использую gdb для отладки этого кода и получения информации о его стеке, например:

0xbffff480:     0x40158ff4      0x40158ff4      0xff0494dc      0x40158ff4
0xbffff490:     0x00000000      0x40016ca0      0xbffff4f8      0x40045de3

0xbffff480 - это то место, где начинается "buf", а последние два слова - EBP и RET, но что, черт возьми, между buf и EBP? Очевидно, у меня нет никаких других локальных перемен. И я также попытался выделить 8 байтов для buf в стеке, он просто продолжится с EBP, но если я выделю 9 или более байтов, между ними всегда будет что-то промежуточное. Может кто-нибудь объяснить это мне, пожалуйста? Большое спасибо! Я на Linux 2.6.9

разборка для основного:

0x080483c4 <main+0>:    push   %ebp
0x080483c5 <main+1>:    mov    %esp,%ebp
0x080483c7 <main+3>:    sub    $0x28,%esp
0x080483ca <main+6>:    and    $0xfffffff0,%esp
0x080483cd <main+9>:    mov    $0x0,%eax
0x080483d2 <main+14>:   add    $0xf,%eax
0x080483d5 <main+17>:   add    $0xf,%eax
0x080483d8 <main+20>:   shr    $0x4,%eax
0x080483db <main+23>:   shl    $0x4,%eax
0x080483de <main+26>:   sub    %eax,%esp
0x080483e0 <main+28>:   movb   $0xff,0xfffffff3(%ebp)
0x080483e4 <main+32>:   lea    0xffffffe8(%ebp),%eax
0x080483e7 <main+35>:   mov    %eax,(%esp)
0x080483ea <main+38>:   call   0x80482e4
0x080483ef <main+43>:   leave
0x080483f0 <main+44>:   ret

Ответы [ 4 ]

4 голосов
/ 12 ноября 2010

Это будет отступ . Ваш компилятор, вероятно, выравнивает EBP на 8-байтовой границе, потому что с выровненной памятью почти всегда проще и быстрее работать (с точки зрения процессора). Некоторые типы данных даже требуют правильного выравнивания для работы.

Вы не видите никакого заполнения, когда выделяете только 8 байтов в своем буфере, потому что, в этом случае, EBP уже правильно выровнен.

1 голос
/ 12 ноября 2010

GCC, как известно, в некоторой степени удовлетворен использованием стека. Это часто резервирует немного больше места в стеке, чем строго необходимо. Кроме того, он попытается добиться выравнивания стека 16 байтов, даже если это не является необходимым. Похоже, это то, что происходит с первыми инструкциями (зарезервировано 40 байтов, затем% esp выравнивание по кратному 16).

Код, который вы показываете, однако, содержит странные вещи, особенно последовательность от смещений от 9 до 27: это длинный, медленный, запутанный способ вычитания 16 из% esp, что можно было бы сделать в одном операционном коде , Вычитание некоторых байтов из% esp в этот момент логично при подготовке к вызову внешней функции (puts()), а count (16) учитывает выравнивание, но зачем делать это таким странным образом?

Вполне возможно, что эта последовательность должна быть исправлена ​​каким-либо образом (например, во время соединения) для поддержки либо кода обнаружения перебора стека, либо некоторого рода кода профилирования. Я не могу воспроизвести это на моих собственных системах. Вы должны указать версию gcc и libc, которые вы используете, точные флаги компиляции и дистрибутив Linux (поскольку распространители могут активировать некоторые опции по умолчанию). Рисунок «2.6.9» - это версия ядра, и она не имеет никакого отношения к рассматриваемой проблеме (она просто говорит нам, что система довольно старая).

1 голос
/ 12 ноября 2010

Обычно gcc поддерживает стек, кратный 16, чтобы иметь возможность использовать инструкции SSE.Чтение разборки вашего main было бы поучительно.

0 голосов
/ 12 ноября 2010

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

  1. Восстанавливаемый кадр стека
  2. Проверка стека, чтобы убедиться, что не было искажения

началоможет также содержать выравнивание стека, форсируя один или оба из перечисленных выше

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