2016-05-11 9 views
0

私たちはある種の "ファイバー"を実装しようとしており、ヒープ上に割り当てられたそれぞれの "スタック"を必要としています。C、インラインアセンブリー - mov命令segfaults

//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; 
    ... 
}; 

ファイバーの作成中に、私たちはその「スタック」を割り振り、作成した構造体を後でレディキューで使用できるようにエンキューします。

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たちは、コンテキストを復元する必要があるため、レディキューから取り出した構造体です。明らかに、最初にスタックポインタs.thを復元する必要があります。

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

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

    ... 
} 

ただし、その移動命令はsegfaultになります。どうして?それをどう回避することができますか?

+1

[mcve]を作成する必要があります。 – user694733

+0

http://stackoverflow.com/questions/19392336/gcc-inline-assembly-wont-let-me-overwrite-esp – stark

+1

おそらく、segfaultを引き起こすのは「mov」ではないでしょう。これは 'fib_resume'からの戻り値です。 'fib_resume'関数が動作するためにスタックに十分な情報が含まれていますか?コンパイルされたCコードがスタック上にあると予想していることを知るのはかなり難しいので、ほとんどすべてのオペレーティングシステムはアセンブラでコンテキストの切り替えを行います。 – Art

答えて

1

i386(インラインアセンブラからかなりわかります)では、スタックが大きくなります。つまり、より低いアドレスに向かうので、関数呼び出しはスタックアドレスを減らします。

これは、スレッド/プロセス/ etcにスタックを割り当てるときのことです。それを行う通常の方法は、スタックポインタレジスタを割り当てられたメモリの最後に向けることです。あなたのケースでは

これは次のようになります。

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

、私はまだそれがかなりアセンブラで完全に機能を書くよりも、Cの関数にインラインアセンブラでこれを行うには良いアイデアかどうかわからないんだけど、このすぐに問題を解決する必要があります。

関連する問題