2010-12-08 5 views
1

следующего короткое замыкание программы:C: адрес возврата функции (макинтош)

void foo(int a, int b) { 
     printf("a = %p b = %p\n", &a, &b); 
} 

main() { 
     foo(1, 2); 
} 

нормально, теперь я использовал GDB, чтобы просмотреть эту программу. Я получил как выход:

a = 0x7fff5fbff9ac b = 0x7fff5fbff9a8 

и остановил выполнение после выхода (в foo()). Теперь я изучил 0x7fff5fbff9ac и содержание было:

1 .... правильный

затем 0x7fff5fbff9a8 и содержание:

2 ... правильно

теперь я хотел, чтобы посмотреть обратный адрес функции и исследовали (а + 4 байта) с:

х/г 0x7fff5fbff9b1 (8 байт !! адреса, поэтому "G" (гигантское слово))

и его содержание было:

(gdb) x/g 0x7fff5fbff9b1 
0x7fff5fbff9b1: 0xd700007fff5fbff9 

НО: ЭТО НЕ ВОЗВРАЩАЕТСЯ ДОПОЛНЕНО! где моя вина?

+0

Что по-другому на MAC? есть ли у кого-то какие-то трудности? – 2010-12-08 17:56:13

ответ

1

Во-первых, &a + 4 - 0x7FFF5FBFF9B0, так что вы ищете одно байтовое смещение от того места, где вы думаете.

Во-вторых, сохраненный указатель кадра находится между a и обратным адресом, и это значение, которое вы видите.

3

В вашем вопросе есть целая куча ошибочных предположений.

Вы предполагаете, что число аргументов передаются в стеке непосредственно над адресом возврата (поскольку они находятся в многих --not всех --x86 АБИСА под умолчанием призывающей конвенции о). Если это так, то сразу после вызова ваш стек будет выглядеть так:

// stack frame of main() 
// ... 
value of b 
value of a 
return address <--- stack pointer 

Однако, ваше предположение неверное. Вы скомпилировали свой код в 64-битный исполняемый файл (о чем свидетельствует размер указателя, который вы печатаете). В OS X ABI, в 64-битном Intel-исполнителе, первые несколько целых аргументов передаются в регистре, а не в стеке. Таким образом, сразу после вызова, стек фактически выглядит следующим образом:

// stack frame of main() 
// ... 
return address <--- stack pointer 

Поскольку вы берете адрес a и b, они будут записаны в стек в какой-то момент перед вызовом printf() (если компилятор действительно умный, и понимает, что на самом деле ему не нужно направлять printf() действительных указателей, потому что он не будет использовать указанное значение, но это было бы довольно злым, поскольку оптимизация идет), но вы действительно не знать, где они будут относиться к обратному адресу; на самом деле, поскольку 64-разрядная ABI обеспечивает красную зону , вы даже не знаете, находятся ли они выше или ниже указателя стека.Таким образом, в то время, что вы распечатать адрес а и Ь, ваш стек выглядит следующим образом:

// stack frame of main() 
// ... 
return address      | 
// ...        | 
// a and b are somewhere down here | <-- stack pointer points somewhere in here 
// ...        | 

В общем, стандартном языке C ничего не говорит о макетах стека, или даже что там должно быть стек вообще. Вы не можете получить такую ​​информацию в любой переносной форме из кода C.

1

То, что вы делаете неправильно, создает целую кучу неправильных и случайных предположений о структуре фрейма стека на вашей конкретной платформе. Откуда у вас эта странная идея о «a + 4 байтах», где, предположительно, есть обратный адрес?

Если вы действительно хотите это сделать, получите документацию для вашей платформы (или сделайте некоторое обратное проектирование), чтобы узнать, где и как именно сохраняется адрес возврата. Производя случайные догадки, а затем спрашивая других людей, почему ваши случайные догадки не дают результатов, которые по какой-то причине ожидают, это не совсем эффективный способ сделать это.

Смежные вопросы