Стек используется для локальных переменных, но также и для промежуточных значений, которые нужны функции.Здесь ваша foo()
функция вызывает bar()
, присваивая ей два указателя, один для строки (argv[1]
), а другой для переменной buf
;эти значения указателя помещаются в стек, а именно в коды операций mov %eax,0x4(%esp)
и mov %edx,(%esp)
.Таким образом, foo()
требуется чуть более 256 байтов стекового пространства.
Более подробно:
0x08048473 <foo+0>:push %ebp
0x08048474 <foo+1>:mov %esp,%ebp
Это стандартный пролог функции: функция будет использовать %ebp
для точекэлементам стека до его вызова (т.е. его аргументов).
0x08048476 <foo+3>:sub $0x118,%esp
Некоторое пространство в стеке зарезервировано, главным образом (но не только) для buf[]
.
0x0804847c <foo+9>:mov 0x8(%ebp),%eax
0x0804847f <foo+12>:add $0x4,%eax
0x08048482 <foo+15>:mov (%eax),%edx
0x8(%ebp)
- аргумент функции argv
;эти коды операций извлекают указатель из argv[1]
и сохраняют результат в %edx
.Это станет первым аргументом для bar()
.
0x08048484 <foo+17>:lea -0x100(%ebp),%eax
. Сохраняет в %eax
адрес buf[]
- компилятор решил, что buf[]
должен находиться в верхних 256 байтах.пространства стека, зарезервированного с помощью sub
.
0x0804848a <foo+23>:mov %eax,0x4(%esp)
0x0804848e <foo+27>:mov %edx,(%esp)
Два аргумента для bar()
помещаются в стек (фактически, записанные в двух верхних позициях стека, %esp
уже настроены).
0x08048491 <foo+30>:call 0x8048454 <bar>
bar()
вызывается.
0x08048496 <foo+35>:leave
0x08048497 <foo+36>:ret
leave
отменяет пролог (это эквивалентно mov %ebp, %esp; pop %ebp
).ret
выходит из функции.
Известно, что GCC перераспределяет бит в стеке;здесь он мог бы зарезервировать 264 байта вместо 280. Это, кажется, артефакт его внутреннего оптимизатора распределения регистров (дополнительные слоты стека были использовались для хранения промежуточных значений, но оптимизатор наконец нашел способы сохранитьтолько соответствующие значения в регистрах).