在内存中创建和使用新堆栈

时间:2011-08-31 16:56:54

标签: c linux stack

出于某些特殊原因(请不要问我为什么),对于某些功能,我想使用单独的堆栈。例如,假设我希望函数malloc使用不同的堆栈进行处理,我需要在调用之前切换到我新创建的堆栈,并在完成后返回到程序使用的原始堆栈。所以算法会是这样的。

switch_to_new_stack
call malloc
swith back to the original stack

最简单,最有效的方法是什么?有什么想法吗?

2 个答案:

答案 0 :(得分:3)

它可能不符合您对简单或高效的定义,但以下可能是一种方法:

#include <stdio.h>
#include <stdlib.h>

#include <ucontext.h>

/* utility functions */
static void getctx(ucontext_t* ucp)
{
    if (getcontext(ucp) == -1) {
        perror("getcontext");
        exit(EXIT_FAILURE);
    }
}

static void print_sp()
{
#if defined(__x86_64)
    unsigned long long x; asm ("mov %%rsp, %0" : "=m" (x));
    printf("sp: %p\n",(void*)x);
#elif defined(__i386)
    unsigned long x; asm ("mov %%esp, %0" : "=m" (x));
    printf("sp: %p\n",(void*)x);
#elif defined(__powerpc__) && defined(__PPC64__)
    unsigned long long x; asm ("addi %0, 1, 0" : "=r" (x));
    printf("sp: %p\n",(void*)x);
#elif defined(__powerpc__)
    unsigned long x; asm ("addi %0, 1, 0" : "=r" (x));
    printf("sp: %p\n",(void*)x);
#else
    printf("unknown architecture\n");
#endif
}


/* stack for 'my_alloc', size arbitrarily chosen */
static int malloc_stack[1024];
static ucontext_t malloc_context; /* context malloc will run in */
static ucontext_t current_context; /* context to return to */

static void my_malloc(size_t sz)
{
    printf("in my_malloc(%zu) ", sz);
    print_sp();
}

void call_my_malloc(size_t sz)
{
    /* prepare context for malloc */
    getctx(&malloc_context);
    malloc_context.uc_stack.ss_sp = malloc_stack;
    malloc_context.uc_stack.ss_size = sizeof(malloc_stack);
    malloc_context.uc_link = &current_context;
    makecontext(&malloc_context, (void(*)())my_malloc, 1, sz);

    if (swapcontext(&current_context, &malloc_context) == -1) {
        perror("swapcontext");
        exit(EXIT_FAILURE);
    }
}

int main()
{
    printf("malloc_stack = %p\n", (void*)malloc_stack);
    printf("in main ");
    print_sp();
    call_my_malloc(42);
    printf("in main ");
    print_sp();
    return 0;
}

这适用于支持makecontext(3)的所有平台。从手册页引用(我也得到了示例代码的灵感):

  

ucp-&gt; uc_stack的解释与sigaltstack(2)中的解释一样,即,此结构包含要用作堆栈的内存区域的起始和长度,而不管堆栈的增长方向如何。因此,用户程序不必担心这个方向。

PPC64的样本输出:

$ gcc -o stack stack.c -Wall -Wextra -W -ggdb -std=gnu99 -pedantic -Werror -m64 && ./stack
malloc_stack = 0x10010fe0
in main sp: 0xfffffe44420
in my_malloc(42) sp: 0x10011e20
in main sp: 0xfffffe44420

答案 1 :(得分:1)

GCC支持分割堆栈,有点像你描述的那样。

http://gcc.gnu.org/wiki/SplitStacks

该项目的目标不同,但实施将按您的要求进行。

  

拆分堆栈的目标是允许根据需要自动增长的不连续堆栈。这意味着您可以运行多个线程,每个线程从一个小堆栈开始,并根据程序的要求增加和缩小堆栈。在编写多线程程序时,不再需要考虑堆栈要求。典型的多线程程序的内存使用量可能会显着降低,因为每个线程不需要最坏情况的堆栈大小。可以在32位地址空间中运行数百万个线程(完整的NPTL线程或协同例程)。