2013-04-21 36 views
9

OSコースの練習として、単純なユーザーレベルのスレッドライブラリをコーディングしようとしています。最初のステップとして、私はプログラムを実行し、最初のプログラムを残す関数にジャンプしようとしています。コードはこれまでです:Cとアセンブリを持つ単純なスレッドをコードします。

初期プログラム:

#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <assert.h> 

#define STACK_SIZE (sizeof(void *) * 512) 


void proc2() //This is the function that should run as the thread. 
{ 
    int i; 
    for(i=0;i<30;i++) 
    { 
     printf("Here I am!\n"); 
     sleep(0.5); 
    } 
    exit(0); 
} 

void* malloc_stack() //used to malloc the stack for the new thread. 
{ 
    void *ptr = malloc(STACK_SIZE + 16); 
    if (!ptr) return NULL; 
     ptr = (void *)(((unsigned long)ptr & (-1 << 4)) + 0x10); //size align 
    return ptr; 
} 

int main() 
{ 
    int *bp, *sp; 
    sp = malloc_stack(); 
    bp = (int*) ((unsigned long)sp + STACK_SIZE); 
    proc1(&proc2,sp,bp); //the actual code that runs the thread. Written in assembly 
    assert(0); 
} 

そして私は、単純な組立3つの引数を取りPROC1と呼ばれるコード(命令ポインタとして使用)関数へのポインタ、スタックを書きました現在のレジスタをこれらの値に置き換えます。

.globl proc1 
proc1: 
movq %rdx, %rbp  #store the new base pointer 
movq %rsi,%rsp   #store the new stack pointer 
jmp  %rdi    #jump to the new instruction pointer. 

しかし、私はこのコードを実行すると、私が取得することは、セグメンテーションフォールトである:私が書いたコードです。ここでエラーを見つけるのを手伝ってください。

gcc -g test.c switch.s 
gdb a.out 
run 

をしかし、それは./a.outのように一人でRUSときには、それは動作しません!!!!:私は、次のコマンドを使用してGDBの下でそれを実行したとき

は、まあ、それが正常に動作しています 助けてください。

ありがとうございます。 jmpmovq %rax,%rspを書かれており、%rspが明確に要求されるされる前に、あなたのあなたのアセンブリの上部にmovqは(まあ、あなたの前に編集した:-)「でした」)

movq dst,src 

が、あなたのmovqとして書かれている

+1

、あなたはおそらくしたくない "&PROC2" ... Q:あなたのコンパイラ/デバッガは何ですか? GCCとGDB?途中でキー変数を見て、デバッガでコードをステップ実行しようとしましたか?そうでない場合は、どうしてですか? – paulsm4

+6

segfaultが発生した場合、プログラマは通常、segfaultが100%繰り返し可能な場合は、デバッガを起動してsegフォルトが正確に発生した場所を確認します。あなたもそうしなければならないし、おそらく質問を更新してください。 – hyde

+1

@ paulsm4関数のアドレスを取るときには '&'を使うのがいいですし、何が起こっているのかを(おそらく)明確にするので、多くの人がそれを好きです。 – hyde

答えて

2

dst。それは明らかに間違っています。

+0

まだ動作していません。まだ – user2290802

+0

-1:これは明らかにAT&T構文であり、オペランドの順序はAT&T構文のsrc、destです。 Intel構文をAT&T構文と混同しているようです。インテルの構文では、オペランドの順序はdest、srcです。 – nrz

+0

@nrz:OPが彼の質問を編集しました。以前は、(dst、src)の順番でスタックからレジスタにパラメータを引き出していました。おそらく、彼は一つの構文で一つの行を組み立てていなかったし、次の行をもう一つの行で組み立てていなかっただろう。当時私が推測していたのは、コンパイラの出力から(dst、src)の順番をつかんだということでしたが、別の場所から取得した可能性もあります。 – torek

4

は以下の通りCソースに直接アセンブリ命令を含むようにコードを変更してみてください:

void proc1(void (*fun)(), int *sp, int *bp){ 
    register int *sptr asm ("%rsi") = sp; 
    register int *bptr asm ("%rdx") = bp; 
    register void (*fptr)() asm ("%rdi") = fun; 

    asm (
     "mov %rdx, %ebp\n" 
     "mov %rsi, %esp\n" 
     "jmp *%rdi\n" 
    ); 
} 

上記のコードは、コードが正しいと思われるがproc1のパラメータ(右レジスタにあることを保証しますwrt the abi)。 jmp引数の前に*があることに注意してください。私のgnuのバージョンは、あなたのコードを最初に試したときに警告しました。あなたはそれを正しくデバッグすることができるはず-gでコンパイルされた上記の機能、およびコード(CPUの内容をチェックするためにproc1info registersbreakpoint命令を使用)で


問題は常に%rbp以上でなければならない%rspポインタ(スタックを下方に成長)に実際にあります。

proc1(&proc2, bp, bp); 

2小さな発言:単純に問題を修正する必要があり、メインにproc1に代わり、SPのBPを渡す

  • ASMバージョンのCコードでproc1プロトタイプを与えることを忘れないでください:

    extern void proc1(void (*)(), int *, int *); 
    
  • sleep libcの関数はunsigned long、ないfloatを取ります。

    初心者のための
    sleep(1); 
    
+0

ありがとうございました。それが問題を解決しました。実際に私はspとbpを混同しています。関数プロトタイプを思い出してくれてありがとう。GCCがなぜ私に睡眠について警告しなかったのだろうか?多分、私はウォールオプションを使用していたはずです。再度、感謝します。 – user2290802

+0

私は知らない。私は '-Wall'も使用しませんでしたが、私は(それは良い方法です)。 – didierc

関連する問題