I'm trying to code a simple user-level thread library as an exercise for my OS course. As the first step, I am trying to run a program and jump to a function leaving the first program. The code so far is this:
The initial program:
#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);
}
And then I wrote a simple assembly code called proc1 that takes three arguments, pointer to a function (used as the instruction pointer), stack pointer and base pointer and replace the current registers with these values. The code I wrote is:
.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.
But when I run this code, what I get is a segmentation fault. Please help me to find the error here.
Well it's working correctly when I ran it under GDB using the following commands:
gcc -g test.c switch.s
gdb a.out
run
but when it rus alone as in ./a.out, it doesn't work!!!! Please help.
Thanks in advance.
C does not contain any built-in support for multithreaded applications. Instead, it relies entirely upon the operating system to provide this feature. This tutorial assumes that you are working on Linux OS and we are going to write multi-threaded C program using POSIX.
In the main thread (i.e. main function; every program has one main thread, in C/C++ this main thread is created automatically by the operating system once the control passes to the main method/function via the kernel) we are calling pthread_cond_signal(&cond1); .
Try changing your code to include the assembly instructions directly in the C source as follow:
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"
);
}
The above code ensures that the parameters to proc1
are in the right registers (although your code seems to be correct wrt the abi). Note the *
in front of the jmp
argument, which my version of gnu as warned about when I first tried your code.
With the above function, and code compiled with -g
you should be able to debug it properly (use the breakpoint
instruction on proc1
and info registers
to check the content of the cpu).
The issue is actually on the %rsp
pointer, which must always be equal to or greater than %rbp
(the stack grows downward). Simply passing bp instead of sp to proc1
in main should fix the issue:
proc1(&proc2, bp, bp);
2 small remarks:
don't forget to give proc1
prototype in the C code for the asm version:
extern void proc1(void (*)(), int *, int *);
the sleep
libc function only take unsigned long
, not float
.
sleep(1);
Your movq
at the top of your assembly are (well, "were" before you edited :-) ) written as
movq dst,src
but your movq
before the jmp
is written movq %rax,%rsp
and %rsp
is clearly the desired dst. That's obviously wrong, not sure about anything else.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With