It probably doesn't fit your definition of easy or efficient, but the following could be one way to do it:
#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 = ¤t_context;
makecontext(&malloc_context, (void(*)())my_malloc, 1, sz);
if (swapcontext(¤t_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;
}
This should work on all platforms where makecontext(3) is supported. Quoting from the manpage (where I also got the inspiration for the example code):
The interpretation of ucp->uc_stack is just as in sigaltstack(2), namely, this struct contains the start and length of a memory area to be used as the stack, regardless of the direction of growth of the stack. Thus, it is not necessary for the user program to worry about this direction.
Sample output from 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
man 3 makecontext?mallocisn't on the stack; any stack space used bymallocis going to be local to the call itself, and will be released as soon asmallocreturns. I can only take your word for it that you need to do this, but I can't think of a good reason.