Page 1 of 1

How to execute an executable on same virtual address?

Posted: Wed Oct 12, 2011 5:07 pm
by Jezze
Hi,

First of, my operating system does not have multitasking which might be a factor in the following text.

Now, to the problem.

I can, within a system call, start an executable by parsing the elf header, set up the page directory and tables needed and then start the program from the virtual address. So far so good.

But this only works if the caller does not share the same virtual address as the program to be executed. If I have two programs with different physical addresses that share the same virtual address this does not work. It is not very hard to figure out why, it is because as soon as I switch over to the new page directory all pages for the old program disappears meaning as soon as the system call returns it page faults.

I'm not sure how to solve this. I was thinking it should be possible in the system call to set some registers like eip or ebp to the entry point of the new program before returning from the system call so that it will start executing at the address for the new program (just like you do when you enter usermode basically) but I have not managed to make this work and unsure if that is the way to go.

Anyone here with a solution?

Re: How to execute an executable on same virtual address?

Posted: Wed Oct 12, 2011 6:22 pm
by gerryg400
I was thinking it should be possible in the system call to set some registers like eip or ebp to the entry point of the new program before returning from the system call so that it will start executing at the address for the new program (just like you do when you enter usermode basically) but I have not managed to make this work and unsure if that is the way to go.
It's certainly possible and it's how my 'exec' works. I have a system call that reads/writes the registers (including segment registers) of a thread. A thread syscalls to read its registers, modify some of them (I modify CS and SS (to switch to ring 3) and RIP) and make another syscall to write them back. When the second syscall returns the thread is in the newly exec'ed process. I modify the RSP by another means but it could also be modified this way.

Re: How to execute an executable on same virtual address?

Posted: Wed Oct 12, 2011 7:40 pm
by Jezze
Thanks for the reply!

After a bit of fiddling I sort of got some of it to work. If I set eip to the address of the virtual address (0x8048080 normally) and subtracted -4 it worked for some of my binaries. Don't know why it had to be -4, probably because eip is incremented somehow which I don't understand. I'll need to do some more research but it is a start at least. Also I need to push the actual arguments to the new program as well...

Re: How to execute an executable on same virtual address?

Posted: Wed Oct 12, 2011 8:01 pm
by gerryg400
I build the stack first. I put the arguments, the argv[], argc and the environment there first and switch to that stack. Then do the jump. I can't imagine why you need to subtract 4. It seems that if you put the correct IP in the stack image, the syscall will return to the correct place.

Are you using rings? Do you switch stacks during a syscall ?

Re: How to execute an executable on same virtual address?

Posted: Fri Oct 14, 2011 1:56 pm
by Jezze
Hi again!

I did exactly what you said and it worked out perfectly. The problem was of course that I hadn't set up the stack properly but now it seem to work fine (the new program starts and gets its input arguments). There is just one little detail and that is what I wanted to check with you.

Before I start the new program I save all necessary registers from previous program and also the page directory. Then when the new program exit I've put the return address (the last thing I pushed to the stack before starting the new program) to a kernel functions that will restore the registers and directory from the previous program. This is basically a task switch. However, what I'm concerned with is that I don't know if that will generate a page fault because the stack is in user space and the return address is in kernel space? How is this normally solved?

I can't test this at the moment because the entire kernel runs with user privileges and is not ready yet to have page protection. Too many other things would break. But when this is solved I will actually be able to have full memory protection enabled.

Re: How to execute an executable on same virtual address?

Posted: Fri Oct 14, 2011 2:50 pm
by turdus
Jezze wrote: the stack is in user space and the return address is in kernel space
You are doing it wrong. When a syscall occurs, the cpu should switch to a safer kernel stack automatically. Nevertheless returning to an address that's on a supervisor page with userspace code selector leads to GPF.
For thus, IPC must be done in kernel space, and the x86 architecture kind enough to copy a defined number of arguments from userspace stack to kernel's when doing a call, and copy return value back. Consult Intel manuals.

Re: How to execute an executable on same virtual address?

Posted: Fri Oct 14, 2011 3:17 pm
by Jezze
Yeah I thought it might. Still one question remains. When a user program exits with a typical return 0. Where does it return? Do you encapsulate a running program somehow so that it automatically sends a syscall like exit()?

EDIT: Nevermind I'll look it up

Re: How to execute an executable on same virtual address?

Posted: Fri Oct 14, 2011 6:42 pm
by gerryg400
Posix goes more or less like this.

Exit() is a syscall with a single parameter. The exit() system call will transform the process into an almost dead zombie. You can free the resources but need to keep the exit value somewhere. Usually the entry in the process table will remain and hold the exit value.

When the program that did the exec() runs again it will usually make another system call - wait(). When this happens you can destroy the remaining part of the zombie process and give its return value to the wait()er.

Re: How to execute an executable on same virtual address?

Posted: Sat Oct 15, 2011 2:50 am
by rdos
Some compilers (at least Open Watcom and Borlands') will start a program like this:

Code: Select all

    call main
    call exit
This means that as soon as the main program is ended, the exit() procedure will be called. It is the exit-procedure that does the clean-up.

As for removing "dead" processes, I have a kernel-thread that does this. The dead process will signal this thread the last thing it does, and then CR3 and page tables would be deallocated by the kernel-thread in a safe context.

Re: How to execute an executable on same virtual address?

Posted: Sun Oct 16, 2011 2:25 pm
by Jezze
Thanks to you guys I now have memory protection working so all user programs have their own memory space and stack. My solution is probably not the best but this is how it ended up:

I let each program get an area of memory that is 65k (0x10000). Of this I reserved the last 0x100 bytes to hold the argv data and the stack for the program. The argv data needs to go into this space because I don't have malloc (by design) or use a particulary sophisticated memory manager. Because I couldn't figure out how to do a "call main; call exit" I just put a system call to exit() instead of return 0 at the end of every user program.

It's not good but it works and it enabled me to finally put my shell in userspace.

Beers on me!