9

我正在尝试编写一个简单的用户级线程库作为我的操作系统课程的练习。作为第一步,我试图运行一个程序并跳转到离开第一个程序的函数。到目前为止的代码是这样的:

初始程序:

#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 的简单汇编代码,它接受三个参数,指向函数的指针(用作指令指针)、堆栈指针和基指针,并用这些值替换当前寄存器。我写的代码是:

.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 中似乎是正确的)。请注意参数*前面的jmp参数,当我第一次尝试您的代码时,我的 gnu 版本警告过它。

使用上面的函数,和-g你一起编译的代码应该可以正常调试(使用breakpoint指令proc1info registers检查cpu的内容)。


问题实际上出在%rsp指针上,它必须始终等于或大于%rbp(堆栈向下增长)。只需将 bp 而不是 sp 传递给proc1in main 即可解决问题:

 proc1(&proc2, bp, bp);

2个小备注:

  • 不要忘记proc1在 asm 版本的 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 回答