【问题标题】:change the stack on the fly of c program即时更改 c 程序的堆栈
【发布时间】:2013-07-23 03:31:03
【问题描述】:

我正在编写以下代码,它将能够更改函数调用的堆栈。但它总是在 printf 上遇到段错误。我用汇编调试了代码,堆栈切换成功。它是创建段错误的 printf 语句,但不确定原因。有人知道我应该进一步研究什么方向吗?

谢谢。

char stack[4000000*4]; 

void foo(int ad) {
    int i = 100;
    int sum = i*i + ad;
    printf("stack changed to %X\n", stack);
}

/* in this example, foo (and its decendents) live on a new stack */
void change_stack(void *newstack) {
    void *ctx[5]; // Jump buffer for setjmp/longjmp.
    if (0 == __builtin_longjmp(ctx)) {
        ctx[2] = newstack; // switch stack  
        __builtin_longjmp(ctx, 1);/* here stack is switched */
    } else {
    /* now live on new stack, can we pass parameters now ? */
    int ad = 20;
    foo(ad);
    }
}

int main (int argc, char** argv)
{
  int i = 10;
  change_stack(stack);
  printf("return, %d\n", i);
  return 0;
}

【问题讨论】:

    标签: c stack heap-memory


    【解决方案1】:

    您无需复制旧堆栈的内容即可切换堆栈。当change_stack 返回时,结果是未定义的(例如,它可能会跳转到地址NULL,从而导致段错误)。此外,局部变量之类的东西也将是未定义的。

    另外,(假设我们在这里讨论的是 x86),堆栈指针在推送时递减。由于您分配的新堆栈指针是stack 数组的基地址(即最低),因此任何推送都会减少该数组之外的指针,也可能导致段错误。

    【讨论】:

    • 感谢您的回复。是的,同时发现段错误来自第二个注释中的原因。我需要使用最高地址。首先请注意,这很好,因为变量是通过帧指针访问的。
    • 您的后一点是正确的,因为变量是通过帧指针访问的。但是,帧存储在堆栈中,因此帧指针仍然指向旧的堆栈空间。
    【解决方案2】:

    对于仍然想玩堆栈并且还在printf 中遇到过 SIGSEGV 的任何人,这里有一点很重要:

    您可以在/path-to-glibc/sysdeps/unix/sysv/linux/tcgetattr.c 下找到printf、__GI___tcgetattr 的子程序之一。里面有一条指令:

    movdqa (%rsp),%xmm0
    

    根据this的回答,它从源地址读取16字节对齐内存。所以你在切换堆栈的时候应该保持%rsp的地址至少16字节地址对齐,否则你会得到一个SIGSEGV。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-03
      • 1970-01-01
      • 1970-01-01
      • 2013-09-30
      • 1970-01-01
      • 2021-06-15
      • 1970-01-01
      相关资源
      最近更新 更多