【问题标题】:How to determine values saved on the stack?如何确定堆栈中保存的值?
【发布时间】:2011-02-04 16:10:16
【问题描述】:
我正在做一些实验,并希望能够查看系统调用期间堆栈中保存的内容(用户登陆进程的保存状态)。根据http://lxr.linux.no/#linux+v2.6.30.1/arch/x86/kernel/entry_32.S,它表明寄存器的各种值保存在堆栈指针的那些特定偏移量处。这是我一直试图用来检查堆栈中保存的内容的代码(这是在我创建的自定义系统调用中):
asm("movl 0x1C(%esp), %ecx");
asm("movl %%ecx, %0" : "=r" (value));
其中 value 是一个无符号长整数。
截至目前,这个值不是预期的(它显示为 ds 的用户值保存了 0)。
我是否正确访问了堆栈指针的偏移量?
另一种可能性是我可以在内核中使用诸如 GDB 之类的调试器来检查堆栈内容吗?我在调试方面没有太多广泛的用途,并且不确定如何调试内核中的代码。任何帮助深表感谢。
【问题讨论】:
标签:
c
linux
assembly
inline-assembly
system-calls
【解决方案1】:
内联汇编比看起来要复杂。试图尽快解决对 GCC 的担忧:
- 如果它修改了处理器寄存器,则必须将这些寄存器放在 clobber 列表中。请务必注意,clobber 列表必须包含您直接(显式)或间接(隐式)更改的ALL寄存器;李>
- 为了强化 (1),条件和数学运算也会改变寄存器,更多地称为状态标志(零、进位、溢出等),因此您必须通过添加 "cc" 来通知它到破坏者名单;
- 如果修改不同的(随机读取)内存位置,则添加“memory”;
- 如果修改了输入/输出参数中未提及的内存,请添加 volatile 关键字;
那么,你的代码就变成了:
asm("movl 0x1C(%%esp), %0;"
: "=r" (value)
: /* no inputs :) */
/* no modified registers */
);
输出参数不需要在 clobber 列表中,因为 GCC 已经知道它将被更改。
另外,由于你想要的只是 ESP 寄存器的值,你可以避免这样做的所有痛苦:
register int esp asm("esp");
esp += 0x1C;
它可能无法解决您的问题,但这是要走的路。如需参考,请查看this、this 和this。
【解决方案2】:
不需要内联汇编。 entry_32.S 推送到堆栈以进行系统调用的已保存状态被布置为 struct pt_regs,您可以像这样获得指向它的指针(您需要包含 <asm/ptrace.h> 和/或 <asm/processor.h>直接或间接):
struct pt_regs *regs = task_pt_regs(current);
【解决方案3】:
请记住,x86_64 代码通常会在寄存器中传递值(因为它有很多),所以堆栈上不会有任何内容。检查 gcc 中间输出 (-S IIRC) 并在程序集中查找 push。
我不熟悉调试内核代码,但 gdb 肯定更好地以交互方式检查堆栈。