Make Stack Pointer to a mmap returned pointer. (Linux, 32bit VM)
I'm trying to move my stack pointer to a mmap-ed region to simulate a context switch, but somehow the code below always give a segmentation error:
C:
struct savectx {
void *regs[JB_SIZE];
};
struct savectx* initctx=(struct savectx*)malloc(sizeof(savectx));
void *newsp;
if ((newsp=mmap(0,STACK_SIZE,PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS,0,0))==MAP_FAILED){
perror("mmap failed");
}
initctx->regs[4]=newsp;
restorectx(initctx,0);
x86:
restorectx:
movl 4(%esp),%ecx /*Move jump buffer addr to ecx */
movl 8(%esp),%eax /*Longjmp return value */
movl (JB_SP*4)(%ecx),%esp /*JB_SP is defined to be 4,*/
The program fails on the last line of the 开发者_JAVA百科assembly.
For malloc I know that I might have to add 0x000f0000 to the pointer, but what about mmap? Or how do we make the stack adjust to the mmapp-ed location. (man page for mmap: http://linux.die.net/man/3/mmap, compiled with GCC on ubuntu)
Linux (or UN*X in general) already has functions to perform this sort of context substitution:
setcontext()
makecontext()
If you use those, you can substitute the entire initial register set (including the stackpointer) by setting up a suitable ucontext_t
/ struct sigcontext
(the uc_mcontext
member of ucontext_t
). Calling setcontext()
then becomes kind-of an extended longjmp()
.
A usage example can be found in the Wikipedia article on setcontext()
.
For the Linux definition of ucontext_t
, see:
ucontext_t
: Linux sourcecode,struct sigcontext
: Linux sourcecode, x86 architecture definition,
(this is architecture-dependent - so x86, ARM, PPC, MIPS, ... all have their own, and this is what contains the register set including the stackpointer).
So the problem was actually that mmap grows at the opposite direction of the stack (which, sadly, I forgot). So to assign the pointer, I just had to assign (mmaped_stack+stack_size) instead of just the pointer.
精彩评论