【问题标题】: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 的担忧:

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

    那么,你的代码就变成了:

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

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

    另外,由于你想要的只是 ESP 寄存器的值,你可以避免这样做的所有痛苦:

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

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

    【讨论】:

      【解决方案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 肯定更好地以交互方式检查堆栈。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-06-23
          • 2012-11-28
          • 2012-07-21
          • 1970-01-01
          • 1970-01-01
          • 2020-11-17
          • 2015-06-17
          • 2013-02-25
          相关资源
          最近更新 更多