C: адрес возврата функции (mac) - PullRequest
1 голос
/ 08 декабря 2010

следующая короткая программа 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 байта) с помощью:

x / g 0x7fff5fbff9b1 (адрес 8 байтов !!, следовательно, "g" (гигантское слово))

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

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

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

Ответы [ 3 ]

3 голосов
/ 09 декабря 2010

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

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

// 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 обеспечивает красную зону , вы даже не знаете, находятся ли они выше или ниже указателя стека. Таким образом, в то время, когда вы распечатываете адреса a и b, ваш стек выглядит так:

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

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

1 голос
/ 09 декабря 2010

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

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

1 голос
/ 09 декабря 2010

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

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

...