简体   繁体   中英

C,inline assembly - mov instruction segfaults

We're trying to implement some kind of "fibers" and want for each a "stack" allocated on the heap, let's say of fixed size somewhere near 2MB, for now.

//2MB ~ 2^21 B = 2097152 B
#define FIB_STACK_SIZE 2097152

#define reg_t uint32_t

typedef struct fiber fiber;
struct fiber{
    ...
    //fiber's stack
    reg_t esp;
    ...
};

During creation of a fiber, we allocate that "stack" and enqueue the created struct for later use in a ready queue.

void fib_create(...){
    //fiber struct itself
    f = malloc(sizeof(*f)); //f later enqueued
    ...     
    //fiber stack
    f->stack = malloc(FIB_STACK_SIZE);
    f->esp = (reg_t)f->stack;
    ...
}

fib is the struct taken from the ready queue for which we need to restore the context.

Obviously, we first need to restore the stack pointer s.th. we can restore everything else:

void fib_resume(){
    //assumes `fib' holds fiber to resume execution

    //restore stack pointers
    __asm__(
        "movl %0, %%esp;"
        :
        :"rm"(fib->esp)
        );

    ...
}

However, that move instruction will result in a segfault. Why? And how can we circumvent that?

On i386 (which is pretty apparent from the inline assembler) the stack grows down. That means towards lower addresses, so function calls will decrement the stack address.

This means that when we're allocating a stack for a thread/process/etc. the normal way of doing it is to point the stack pointer register at the end of the allocated memory.

In your case this should be:

f->esp = (reg_t)f->stack + FIB_STACK_SIZE;

I'm still not sure if it's a good idea to do this with inline assembler in a C function rather than writing the function completely in assembler, but this should resolve the immediate problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM