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 нулевым значением на производительность (я понимаю, что это очень простая операция, но в любом случае), и мы должны ее избегать? Заранее спасибо.