如何确定堆栈中保存的值?

时间:2010-04-06 04:22:34

标签: c linux assembly inline-assembly system-calls

我正在进行一些实验,并希望能够在系统调用期间查看堆栈中保存的内容(用户登陆过程的已保存状态)。根据{{​​3}},它表明寄存器的各种值保存在堆栈指针的那些特定偏移处。这是我一直试图用来检查堆栈上保存的代码的代码(这是我创建的自定义系统调用):

asm("movl 0x1C(%esp), %ecx");
asm("movl %%ecx, %0" : "=r" (value));

其中value是unsigned long。

截至目前,此值不是预期的值(显示为ds的用户值保存0)。

我是否正确访问了堆栈指针的偏移量?

另一种可能性是我可以在内核中使用调试器(如GDB)来检查堆栈内容吗?我没有广泛使用调试,也不知道如何在内核中调试代码。任何帮助深表感谢。

3 个答案:

答案 0 :(得分:5)

无需内联汇编。 entry_32.S为系统调用推送到堆栈的已保存状态被设置为struct pt_regs,您可以像这样获得指向它的指针(您需要包含<asm/ptrace.h>和/或<asm/processor.h>直接或间接地):

struct pt_regs *regs = task_pt_regs(current);

答案 1 :(得分:4)

内联汇编比看起来更棘手。试图尽快解决海湾合作委员会的担忧:

  1. 如果它修改了处理器寄存器,则必须将这些寄存器放在clobber列表中。重要的是要注意,clobber列表必须包含您直接更改的 ALL 寄存器(读取显式)或间接更改(读取隐式);
  2. 为了强化(1),条件和数学运算也会改变寄存器,更多称为状态标志(零,进位,溢出等),因此您必须通过添加“cc”来通知它到了clobber列表;
  3. 添加“内存”,如果它修改了不同的(随机读取)内存位置;
  4. 如果修改了输入/输出参数中未提及的内存,请添加 volatile 关键字;
  5. 然后,您的代码变为:

    asm("movl 0x1C(%%esp), %0;"
        : "=r" (value)
        : /* no inputs :) */
        /* no modified registers */
    );
    

    输出参数不需要在clobber列表中,因为GCC已经知道它将被更改。

    或者,既然你想要的只是ESP注册的价值,你可以避免这样做的所有痛苦:

    register int esp asm("esp");
    esp += 0x1C;
    

    它可能无法解决您的问题,但这是要走的路。如需参考,请检查thisthisthis

答案 2 :(得分:0)

请记住,x86_64代码通常会传递寄存器中的值(因为它有很多),因此堆栈中不会有任何内容。检查gcc中间输出(-S IIRC)并在程序集中查找push

我不熟悉调试内核代码,但gdb绝对可以更好地以交互方式检查堆栈。