Помогите разобраться в самой базовой дизассемблировании main () в GDB

Heyo,

Я написал эту очень простую функцию main, чтобы поэкспериментировать с дизассемблированием, а также увидеть и, надеюсь, понять, что происходит на нижнем уровне:

int main() {
  return 6;
}

Использование gdb для отключения main производит следующее:

0x08048374 <main+0>:    lea    0x4(%esp),%ecx
0x08048378 <main+4>:    and    $0xfffffff0,%esp
0x0804837b <main+7>:    pushl  -0x4(%ecx)
0x0804837e <main+10>:   push   %ebp
0x0804837f <main+11>:   mov    %esp,%ebp
0x08048381 <main+13>:   push   %ecx
0x08048382 <main+14>:   mov    $0x6,%eax
0x08048387 <main+19>:   pop    %ecx
0x08048388 <main+20>:   pop    %ebp
0x08048389 <main+21>:   lea    -0x4(%ecx),%esp
0x0804838c <main+24>:   ret  

Вот мое лучшее предположение относительно того, что я думаю, и что мне нужно построчно помочь:

lea 0x4 (% esp),% ecx

Загрузить адрес esp + 4 в ecx. Почему мы добавляем 4 к esp?

Я где-то читал, что это адрес аргументов командной строки. Но когда я сделал x / d $ ecx , я получил значение argc. Где хранятся фактические значения аргументов командной строки?

и $ 0xfffffff0,% esp

Выровнять стек

pushl -0x4 (% ecx)

Вставить адрес, где изначально был esp, в стек. Какова цель этого?

push% ebp

Поместить базовый указатель в стек

mov% esp,% ebp

Переместить текущий указатель стека в базовый указатель

push% ecx

Поместить адрес исходного esp + 4 в стек. Почему?

mov $ 0x6,% eax

Я хотел вернуть здесь 6, поэтому я предполагаю, что возвращаемое значение хранится в eax?

pop% ecx

Восстановить ecx до значения, которое находится в стеке. Почему нам нужно, чтобы ecx был esp + 4, когда мы вернемся?

pop% ebp

Восстановить ebp до значения, которое находится в стеке

lea -0x4 (% ecx),% esp

Восстановить исходное значение esp

ret

Я новичок, когда дело касается сборки, поэтому любая помощь будет отличной! Также, если вы видите какие-либо ложные утверждения о том, что, как я думаю, происходит, пожалуйста, поправьте меня.

Большое спасибо! : // Возможно, что-то сделаем ... str = "Тест"; Console.WriteLine (str); и String str; // Возможно, что-то сделаем ... str = "Тест"; Console.WriteLine (str); ...

Давайте сравним две части кода:

String str = null;
//Possibly do something...
str = "Test";
Console.WriteLine(str);

и

String str;
//Possibly do something...
str = "Test";
Console.WriteLine(str);

Я всегда думал, что эти части кода равны. Но после того, как я построил этот код (режим выпуска с проверенной оптимизацией) и сравнил сгенерированные методы IL, я заметил, что в первом примере есть еще две инструкции IL:

1-й пример кода IL:

.maxstack 1
.locals init ([0] строка str)
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldstr "Тест"
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: вызов void [mscorlib] System.Console :: WriteLine (строка)
IL_000e: ret

2-й пример кода IL:

.maxstack 1
.locals init ([0] строка str)
IL_0000: ldstr "Тест"
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: вызов void [mscorlib] System.Console :: WriteLine (строка)
IL_000c: ret

Возможно, этот код оптимизирован JIT-компилятором? Так влияет ли инициализация локальной переменной bethod нулевым значением на производительность (я понимаю, что это очень простая операция, но в любом случае), и мы должны ее избегать? Заранее спасибо.

7
задан petro.sidlovskyy 20 January 2011 в 19:24
поделиться