Luke McCarthy
Luke McCarthy

Reputation: 919

Call C function with different stack pointer (gcc)

I'm looking for a way to call a C function in a different stack, i.e. save the current stack pointer, set the stack pointer to a different location, call the function and restore the old stack pointer when it returns.

The purpose of this is a lightweight threading system for a programming language. Threads will operate on very small stacks, check when more stack is needed and dynamically resize it. This is so that thousands of threads can be allocated without wasting a lot of memory. When calling in to C code it is not safe to use a tiny stack, since the C code does not know about checking and resizing, so I want to use a big pthread stack which is used only for calling C (shared between lightweight threads on the same pthread).

Now I could write assembly code stubs which will work fine, but I wondered if there is a better way to do this, such as a gcc extension or a library which already implements it. If not, then I guess I'll have my head buried in ABI and assembly language manuals ;-) I only ask this out of laziness and not wanting to reinvent the wheel.

Upvotes: 8

Views: 1855

Answers (2)

David Leonard
David Leonard

Reputation: 1748

Although deprecated in POSIX.1-2008, you could use makecontext() and swapcontext():

#define _XOPEN_SOURCE 500
#include <stdio.h>                                                          
#include <ucontext.h>                                                       

void f();

int main()
{
    static char f_stack[4096];
    static ucontext_t uc_main;
    static ucontext_t uc_f;

    getcontext(&uc_f);
    uc_f.uc_stack.ss_sp = f_stack;
    uc_f.uc_stack.ss_size = sizeof f_stack;
    uc_f.uc_link = &uc_main;
    makecontext(&uc_f, f, 1, 2);  /* f1(2) */

    f(1);
    swapcontext(&uc_main, &uc_f);
    f(3);
}

void f(int arg1)
{
    int i;
    printf("f(%d) stack %p\n", arg1, &i);
}

outputs

f(1) stack 0x7ffc5dff9274
f(2) stack 0x564b1538a3f4
f(3) stack 0x7ffc5dff9274

See makecontext, swapcontext (SUSv2, POSIX.1-2001)

Upvotes: 0

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215193

Assuming you're using POSIX threads and on a POSIX system, you can achieve this with signals. Setup an alternate signal handling stack (sigaltstack) and designate one special real-time signal to have its handler run on the alternate signal stack. Then raise the signal to switch to the stack, and have the signal handler read the data for what function to call, and what argument to pass it, from thread-local data.

Note that this approach is fairly expensive (multiple system calls to change stacks), but should be 100% portable to POSIX systems. Since it's slow, you might want to make arch-specific call-on-alt-stack functions written in assembly, and only use my general solution as a fallback for archs where you haven't written an assembly version.

Upvotes: 2

Related Questions