9

OS コースの演習として、単純なユーザーレベルのスレッド ライブラリをコーディングしようとしています。最初のステップとして、プログラムを実行し、最初のプログラムを離れる関数にジャンプしようとしています。これまでのコードは次のとおりです。

初期プログラム:

#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);
}

次に、proc1 という単純なアセンブリ コードを作成しました。このコードは、関数へのポインター (命令ポインターとして使用)、スタック ポインター、およびベース ポインターの 3 つの引数を取り、現在のレジスターをこれらの値で置き換えます。私が書いたコードは次のとおりです。

.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.

しかし、このコードを実行すると、セグメンテーション違反が発生します。ここでエラーを見つけるのを手伝ってください。

次のコマンドを使用して GDB で実行すると、正しく動作します。

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

しかし、./a.out のように単独で実行すると、機能しません!!!! 助けてください。

前もって感謝します。

4

2 に答える 2

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が正しいレジスターにあることを保証します (ただし、コードは abi に関して正しいようです)。コードを最初に試したときに、私のバージョンの gnu が警告し*た引数の前に注意してください。jmp

上記の関数と、コンパイルされたコードを-g使用すると、適切にデバッグできるはずです (breakpoint命令 on proc1andを使用info registersして、CPU の内容を確認します)。


問題は実際には%rspポインターにあり、常に同じかそれ以上でなければなりません%rbp(スタックは下に向かって成長します)。sp の代わりに bp をproc1main に渡すだけで問題が解決するはずです。

 proc1(&proc2, bp, bp);

2 つの小さな注意事項:

  • proc1asm バージョンの C コードでプロトタイプを指定することを忘れないでください。

    extern void proc1(void (*)(), int *, int *);
    
  • sleeplibc 関数は のみを受け取り、は受け取りunsigned longませんfloat

    sleep(1);
    
于 2013-04-21T10:17:16.630 に答える
2

あなたmovqのアセンブリの一番上にあるのは(まあ、あなたが編集する前は「だった」:-))のように書かれています

movq dst,src

しかし、あなたのmovq前にjmp書かれmovq %rax,%rspており、%rsp明らかに望ましいdstです。それは明らかに間違っており、それ以外についてはわかりません。

于 2013-04-21T08:06:04.617 に答える