GCC 4.3 / 4.4 против MSC 6 на i386 для оптимизации размера - PullRequest
3 голосов
/ 05 сентября 2011

Я не уверен, что я делаю неправильно, но я пробовал читать руководства по соглашениям о вызовах GCC и не нашел там ничего полезного.Моя текущая проблема заключается в том, что GCC генерирует чрезмерно БОЛЬШОЙ код для очень простой операции, как показано ниже.

main.c:

#ifdef __GNUC__
    // defines for GCC
    typedef void (* push1)(unsigned long);
    #define PUSH1(P,A0)((push1)P)((unsigned long)A0)
#else
    // defines for MSC
    typedef void (__stdcall * push1)(unsigned long);
    #define PUSH1(P,A0)((push1)P)((unsigned long)A0)
#endif

int main() {
    // pointer to nasm-linked exit syscall "function".
    // will not work for win32 target, provided as an example.
    PUSH1(0x08048200,0x7F);
}

Теперь давайте создадим и выгрузим его с помощью gcc: gcc -c main.c -Os;objdump -d main.o:

main.o:     file format elf32-i386

Disassembly of section .text:

00000000 <.text>:
   0:   8d 4c 24 04             lea    0x4(%esp),%ecx
   4:   83 e4 f0                and    $0xfffffff0,%esp
   7:   ff 71 fc                pushl  -0x4(%ecx)
   a:   b8 00 82 04 08          mov    $0x8048200,%eax
   f:   55                      push   %ebp
  10:   89 e5                   mov    %esp,%ebp
  12:   51                      push   %ecx
  13:   83 ec 10                sub    $0x10,%esp
  16:   6a 7f                   push   $0x7f
  18:   ff d0                   call   *%eax
  1a:   8b 4d fc                mov    -0x4(%ebp),%ecx
  1d:   83 c4 0c                add    $0xc,%esp
  20:   c9                      leave  
  21:   8d 61 fc                lea    -0x4(%ecx),%esp
  24:   c3                      ret

Это код минимального размера, который я могу получить ... Если я не укажу -O * или не укажу другие значения, он будет иметь длину 0x29 + байт.

Теперь давайте создадим его с помощью компилятора ms c v 6 (да, один из 98 iirc года): wine /mnt/ssd/msc/6/cl /c /TC main.c;wine /mnt/ssd/msc/6/dumpbin /disasm main.obj:

Dump of file main.obj

File Type: COFF OBJECT

_main:
  00000000: 55                 push        ebp
  00000001: 8B EC              mov         ebp,esp
  00000003: 6A 7F              push        7Fh
  00000005: B8 00 82 04 08     mov         eax,8048200h
  0000000A: FF D0              call        eax
  0000000C: 5D                 pop         ebp
  0000000D: C3                 ret

Как заставить GCC генерировать аналогичный по размеру код?какие-нибудь намеки, советы?Разве вы не согласны, что полученный код должен быть таким маленьким?Почему GCC добавляет так много бесполезного кода?Я думал, что это будет умнее, чем такие старые вещи, как msc6, при оптимизации размера.Что мне здесь не хватает?

Ответы [ 2 ]

4 голосов
/ 05 сентября 2011

main () здесь особенное: gcc выполняет дополнительную работу по выравниванию стека в 16 байтов в точке входа в программу.Таким образом, размер результата не сопоставим напрямую ... попробуйте переименовать main () в f (), и вы увидите, что gcc генерирует совершенно другой код.

(скомпилированный код MSVC не нужензаботиться о выравнивании, потому что Windows имеет различные правила для выравнивания стека.)

0 голосов
/ 05 сентября 2011

Это - лучшая справка, которую я могу получить. Я сейчас на Windows и слишком ленив, чтобы войти в свой Linux для тестирования. Здесь (MinGW GCC 4.5.2) код меньше вашего. Одно из отличий заключается в соглашении о вызовах. Конечно, stdcall имеет преимущество в несколько байт по сравнению с cdecl (по умолчанию в GCC, если не указано, или с -O1, и я полагаю, с -Os) для очистки стека.

Вот как я компилирую и результат (исходный код просто скопирован из вашего поста)

gcc -S test.c:

_main:
    pushl   %ebp     #
    movl    %esp, %ebp   #,
    andl    $-16, %esp   #,
    subl    $16, %esp    #,
    call    ___main  #
    movl    $127, (%esp)     #,
    movl    $134513152, %eax     #, tmp59
    call    *%eax    # tmp59
    leave
    ret

gcc -c -o test.o test.c && objdump -d test.o:

test.o:     file format pe-i386


Disassembly of section .text:

00000000 <_main>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   83 e4 f0                and    $0xfffffff0,%esp
   6:   83 ec 10                sub    $0x10,%esp
   9:   e8 00 00 00 00          call   e <_main+0xe>
   e:   c7 04 24 7f 00 00 00    movl   $0x7f,(%esp)
  15:   b8 00 82 04 08          mov    $0x8048200,%eax
  1a:   ff d0                   call   *%eax
  1c:   c9                      leave
  1d:   c3                      ret
  1e:   90                      nop
  1f:   90                      nop
...