Анализ кода сборки - PullRequest
       5

Анализ кода сборки

8 голосов
/ 26 октября 2010
 $ gcc -O2 -S test.c -----------------------(1)
      .file "test.c"
    .globl accum
       .bss
       .align 4
       .type accum, @object
       .size accum, 4
    accum:
       .zero 4
       .text
       .p2align 2,,3
    .globl sum
       .type sum, @function
    sum:
       pushl %ebp
       movl  %esp, %ebp
       movl  12(%ebp), %eax
       addl  8(%ebp), %eax
       addl  %eax, accum
       leave
       ret
       .size sum, .-sum
       .p2align 2,,3
    .globl main
       .type main, @function
    main:
       pushl %ebp
       movl  %esp, %ebp
       subl  $8, %esp
       andl  $-16, %esp
       subl  $16, %esp
       pushl $11
       pushl $10
       call  sum
       xorl  %eax, %eax
       leave
       ret
       .size main, .-main
       .section .note.GNU-stack,"",@progbits
       .ident   "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-9)"

Это код сборки, сгенерированный из этой программы на C:

#include <stdio.h>
int accum = 0;

int sum(int x,int y)
{
   int t = x+y;
   accum +=t;
   return t;
}

int main(int argc,char *argv[])
{
   int i = 0,x=10,y=11;
   i = sum(x,y);
   return 0;
}

Кроме того, это код объекта, сгенерированный из вышеуказанной программы:

$objdump -d test.o -------------------------(2) 

test.o:     file format elf32-i386

Disassembly of section .text:

00000000 <sum>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   8b 45 0c                mov    0xc(%ebp),%eax
   6:   03 45 08                add    0x8(%ebp),%eax
   9:   01 05 00 00 00 00       add    %eax,0x0
   f:   c9                      leave
  10:   c3                      ret
  11:   8d 76 00                lea    0x0(%esi),%esi

00000014 <main>:
  14:   55                      push   %ebp
  15:   89 e5                   mov    %esp,%ebp
  17:   83 ec 08                sub    $0x8,%esp
  1a:   83 e4 f0                and    $0xfffffff0,%esp
  1d:   83 ec 10                sub    $0x10,%esp
  20:   6a 0b                   push   $0xb
  22:   6a 0a                   push   $0xa
  24:   e8 fc ff ff ff          call   25 <main+0x11>
  29:   31 c0                   xor    %eax,%eax
  2b:   c9                      leave
  2c:   c3                      ret

В идеале,листинги (1) и (2) должны быть одинаковыми.Но я вижу, что в листинге (1) есть movl, pushl и т. Д., В то время как mov, push в lising (2).Мой вопрос:

  1. Какая правильная инструкция по сборке фактически выполняется на процессоре?
  2. В листинге (1) я вижу это в начале:

.file "test.c"
    .globl accum
       .bss
       .align 4
       .type accum, @object
       .size accum, 4
    accum:
       .zero 4
       .text
       .p2align 2,,3
    .globl sum
       .type sum, @function 

и это в конце:

.size main, .-main
           .section .note.GNU-stack,"",@progbits
           .ident   "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-9)"

Что это значит?

Спасибо.

Ответы [ 2 ]

13 голосов
/ 26 октября 2010

Инструкция называется MOV независимо от используемого варианта. Суффикс l - это просто соглашение о сборке gcc / AT & T, определяющее размер желаемых операндов, в данном случае 4-байтовых операнда.

В синтаксисе Intel - где есть какая-то двусмысленность - вместо суффикса инструкции обычно помечают параметр памяти указателем требуемого размера (например, BYTE, WORD, DWORD и т. Д.) Это просто еще один способ достичь того же.

89 55 - это правильная последовательность байтов для MOV из 32-разрядного регистра EBP в 32-разрядный регистр ESP. В любом листинге нет ничего плохого.


Указывает файл, из которого был сгенерирован этот код сборки:

.file "test.c"

Говорит, что accum является глобальным символом (переменная C с внешней связью):

    .globl accum

Следующие байты должны быть помещены в секцию bss, это секция, которая не занимает места в объектном файле, но выделяется и обнуляется во время выполнения.

       .bss

Выровненный по 4-байтовой границе:

       .align 4

Это объект (переменная, а не какой-то код):

       .type accum, @object

Это четыре байта:

       .size accum, 4

Здесь определено accum, четыре нулевых байта.

    accum:
       .zero 4

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

       .text

Добавьте до трех байтов заполнения, чтобы убедиться, что мы находимся на границе 4 байта (2 ^ 2):

       .p2align 2,,3

sum - это глобальный символ, и это функция.

    .globl sum
       .type sum, @function 

Размер main "здесь" - "где main начался":

.size main, .-main

Здесь указываются специфичные для gcc параметры стека. Как правило, именно здесь вы решаете иметь исполняемый стек (не очень безопасный) или нет (обычно предпочтительнее).

       .section .note.GNU-stack,"",@progbits

Укажите, какая версия компилятора сгенерировала эту сборку:

       .ident   "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-9)"
0 голосов
/ 26 октября 2010

Список ассемблера и список дизассемблера показывают один и тот же код, но используют другой синтаксис. Добавленный -l является синтаксическим вариантом, используемым gcc. То, что у вас другой синтаксис в инструментах (вывод C-компилятора и дизассемблер), показывает слабость вашей цепочки инструментов.

Демонтаж по смещению 11 в сумме: показывает только некоторые байты мусора. Точка входа в следующую функцию main выровнена по 4 байта, что дает этот пробел, заполненный мусором.

Связка .statements определяется документацией ассемблера. Обычно они не дают никакого исполняемого кода.

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