Оптимизация стека GCC? - PullRequest
2 голосов
/ 14 января 2011

Я просто написал пример кода на C и попытался разобрать его. Ниже приведен пример кода.

void start() {
    char phone[100];
    strcmp(phone, "12312312313");

    char name[100];
    strcmp(name, "eQuiNoX");

    char contact[100];
    strcmp(contact, "PM twitter.com/eQuiNoX__");
}

Когда я разбираю функцию запуска, я получаю следующее: -

08048414 <start>:
 8048414: 55                    push   ebp
 8048415: 89 e5                 mov    ebp,esp
 8048417: 81 ec 58 01 00 00     sub    esp,0x158
 804841d: c9                    leave  
 804841e: c3                    ret   
  1. Я не включил никакой оптимизации. Может кто-нибудь объяснить, почему я получаю 158 вычитаемым из esp, а не из ассемблерного кода, который помещает значения в стек и вызывает метод strcmp? Это потому, что это не зависит от ввода пользователя?
  2. Кроме того, есть ли способ, которым я мог бы сгенерировать extended assembly (я не уверен, что это правильный термин, я просто хочу увидеть ассемблерный код для загрузки значений в стек и вызова функции strcmp). Есть ли способ, которым я мог бы сделать это?
  3. Этот тип поведения специфичен для архитектур процессоров или версий gcc или для обоих?

Ответы [ 4 ]

10 голосов
/ 14 января 2011

Во-первых, strcmp - это стандартная библиотечная функция, поэтому gcc может свободно знать, как она работает.На самом деле это так;это редко генерирует библиотечный вызов.Вы можете попробовать -fno-builtin отключить.

Во-вторых, вы сравниваете с унифицированными значениями.Это, я считаю, неопределенное поведение.Таким образом, компилятор может делать все, что пожелает, включая генерацию случайного кода.

Вы можете попробовать опцию -S, чтобы gcc получил более подробную разборку (или, скорее, отсутствие сборки);альтернативно, если вы скомпилируете с помощью -g (отладка), objdump -S отобразит исходный код вместе с собранным кодом.

Вот пример, который я скомпилировал с помощью gcc -fno-builtin -g -O0 test.c -c, а затем выгрузил с помощью objdump -S test.o:

test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
#include <string.h>

int main() {
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 83 ec 10             sub    $0x10,%rsp
    const char foo[] = "foo";
   8:   8b 05 00 00 00 00       mov    0x0(%rip),%eax        # e <main+0xe>
   e:   89 45 f0                mov    %eax,-0x10(%rbp)
    return strcmp(foo, "bar");
  11:   48 8d 45 f0             lea    -0x10(%rbp),%rax
  15:   be 00 00 00 00          mov    $0x0,%esi
  1a:   48 89 c7                mov    %rax,%rdi
  1d:   e8 00 00 00 00          callq  22 <main+0x22>
}
  22:   c9                      leaveq 
  23:   c3                      retq   
4 голосов
/ 14 января 2011
  1. Поскольку ваш код не влияет на выполнение программы. Все переменные используются в вызовах функций, чьи возвращаемые значения отбрасываются, поэтому компилятор пометил его как неиспользуемый код и решил, что его следует удалить. Если вы хотите сохранить неиспользуемый код, убедитесь, что вы не используете оптимизацию - скомпилируйте с -O0.

  2. См. Мою точку зрения выше.

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

4 голосов
/ 14 января 2011

Что касается инструкции sub esp,0x158, вместо генерации загрузки операций push (которые включают копирование операнда в стек, а не просто резервирование места), обычно компилятор просто резервирует достаточно места для всех локальных переменных с помощью перемещение указателя стека только один раз. Это то, что делает эта инструкция. 0x158 - это 344 в десятичном виде, поэтому он резервирует 300 байтов для массивов и, возможно, некоторое дополнительное пространство для структур, сгенерированных компилятором (или, возможно, для помещения операндов strcmp в стек).

0 голосов
/ 14 января 2011

Кажется, это действительно было оптимизировано.Вы можете попробовать скомпилировать с флагом -O0, чтобы убедиться, что оптимизация не производится (однако я не уверен, что она будет работать).

Или вы можете просто вернуть результаты cmp из функции start, чтобы показать компиляторудействительно используйте их:

int start() {
    char phone[] = "43423432";
    return strcmp(phone, "12312312313");
}
...