Page 1 of 1

_exit syscall in single-tasking?

Posted: Sun May 21, 2017 8:24 am
by Agola
Hello.
I'm developing a very minimal version of my os called MAgola. It's a single-tasking os instead of my multitasking os, Agola.

I want to execute my elf application, then return the system using _exit syscall like calling a C function. However I can't return to os using _exit. System strolls out from its address space and I get an invalid opcode fault as usual.

I use newlib and my crt0 is:

Code: Select all

void _start()
{
    int argc;
    char** argv;

    unsigned int argv_p;

    asm volatile ("movl %%edi, %0" : "=r"(argc));
    asm volatile ("movl %%esi, %0" : "=r"(argv_p));

    argv = (char**) argv_p;

    _init_signal();
    _init();

    exit(main(argc, argv));
}
and _exit is:

Code: Select all

int _exit(int code)
{
   _fini();
   return syscall_exit(code);
}
I jump to elf entry point using a call instruction, so return address is pushed to stack. After syscall_exit, _exit will return using a ret instruction, too and it will pop the return address back and return to the system. But it doesn't work like I thought. And interestingly it works if I use _exit(main(argc, argv)) instead of exit(main(argc, argv)).

How can I return to the system correctly using _exit in single-tasking? I think my elf loader is correct as I use its really similar version in Agola and it works flawlessly.

Thanks in advance.

Re: _exit syscall in single-tasking?

Posted: Sun May 21, 2017 1:00 pm
by dozniak
syscall_exit() should be declared [[noreturn]] and not return back to the process.. problem solved.

Re: _exit syscall in single-tasking?

Posted: Sun May 21, 2017 2:08 pm
by no92
While dozniak is right in saying that syscall_exit should be a noreturn, he's only scratching the surface.

In all implementations that I've seen, exit generally calls _exit (or its equivalent _Exit), that has two jobs and two jobs only: make the syscall to terminate the process (this usually includes cleanup like closing open file descriptors, etc.) and never return, hence the _Noreturn keyword. In other words, the syscall to terminate a process should not return in the first place; the line

Code: Select all

return syscall_exit(code);
is a contradiction in itself.

My C11 spec says that exit(3) should look like this:

Code: Select all

_Noreturn void exit(int status);
Here's the description (see 7.22.4.4):
C11 spec wrote:The exit function causes normal program termination to occur. No functions registered by the at_quick_exit function are called. If a program calls the exit function more than once, or calls the quick_exit function in addition to the exit function, the behavior is undefined.
As for _exit(3), it should be declared as

Code: Select all

_Noreturn void _Exit(int status);
The description is pretty similar:
C11 spec wrote: The _Exit function causes normal program termination to occur and control to be returned to the host environment. No functions registered by the atexit function, the at_quick_exit function, or signal handlers registered by the signal function are called. The status returned to the host environment is determined in the same way as for the exit function (7.22.4.4). Whether open streams with unwritten buffered data are flushed, open streams are closed, or temporary files are removed is implementation-defined.
Long story short: whatever you are doing right there is not standard-compliant nor sensible (Think about it: your exit syscall doesn't terminate the program?)

Re: _exit syscall in single-tasking?

Posted: Sun May 21, 2017 9:27 pm
by Agola
That makes sense. If I declare the _exit as noreturn, how will I return the normal execution of system in a single-tasking OS? In Agola, that is easy, I just go to the next task and clear the process that finished. But MAgola is a single-tasking OS, so OS will stuck and never return.

How can I implement _exit to return the system or patch exit to return the system?

Thanks in advance

Re: _exit syscall in single-tasking?

Posted: Sun May 21, 2017 9:34 pm
by BrightLight
Agola wrote:That makes sense. If I declare the _exit as noreturn, how will I return the normal execution of system in a single-tasking OS? In Agola, that is easy, I just go to the next task and clear the process that finished. But MAgola is a single-tasking OS, so OS will stuck and never return.
I guess you'd probably do it the way DOS had a system call for exiting MZ applications. If your OS is single-tasking, you might have a way of having multiple programs loaded in memory yet only one actually executing (start and stay resident programs.) If, for example, you have shell.exe as your shell, and the user starts app.exe from the shell, when app.exe decides to exit, the OS should probably give control back to shell.exe, starting at the instructions right after the system call that started app.exe.

I think DOS did it this way. And even if it didn't, IMHO, it's a decent design for a single-tasking system.

Just out of interest, why are you writing a single-tasking OS when you say you have a multitasking OS? It's taking a step backward, and so there must be a reason. :?

Re: _exit syscall in single-tasking?

Posted: Mon May 22, 2017 12:10 am
by Boris
Hi,
What is your single task model ?
I guess you have something like a task stack, when you start an app, it comes to the foreground. When that app exits, return to the app which started it.

Re: _exit syscall in single-tasking?

Posted: Mon May 22, 2017 2:01 am
by dozniak
Agola wrote:how will I return the normal execution of system in a single-tasking OS? In Agola, that is easy, I just go to the next task and clear the process that finished. But MAgola is a single-tasking OS, so OS will stuck and never return.

How can I implement _exit to return the system or patch exit to return the system?
Your app was started by something, e.g. a system shell process. Return to it.

Re: _exit syscall in single-tasking?

Posted: Mon May 22, 2017 7:51 am
by Agola
dozniak wrote:
Agola wrote:how will I return the normal execution of system in a single-tasking OS? In Agola, that is easy, I just go to the next task and clear the process that finished. But MAgola is a single-tasking OS, so OS will stuck and never return.

How can I implement _exit to return the system or patch exit to return the system?
Your app was started by something, e.g. a system shell process. Return to it.
How can I return to it? I need to know the next instruction (eip) after the "call <elf_entry_point>" instruction to return execution of system process.
Could saving the interrupt frame (execvx syscall loads the elf) and restoring it work?

Thanks.

Re: _exit syscall in single-tasking?

Posted: Mon May 22, 2017 8:32 am
by Agola
omarrx024 wrote:
Agola wrote:That makes sense. If I declare the _exit as noreturn, how will I return the normal execution of system in a single-tasking OS? In Agola, that is easy, I just go to the next task and clear the process that finished. But MAgola is a single-tasking OS, so OS will stuck and never return.
I guess you'd probably do it the way DOS had a system call for exiting MZ applications. If your OS is single-tasking, you might have a way of having multiple programs loaded in memory yet only one actually executing (start and stay resident programs.) If, for example, you have shell.exe as your shell, and the user starts app.exe from the shell, when app.exe decides to exit, the OS should probably give control back to shell.exe, starting at the instructions right after the system call that started app.exe.

I think DOS did it this way. And even if it didn't, IMHO, it's a decent design for a single-tasking system.

Just out of interest, why are you writing a single-tasking OS when you say you have a multitasking OS? It's taking a step backward, and so there must be a reason. :?
That makes sense. The DOS way looks like the same what I want to do. But I don't know how will I know the EIP after the call instruction (after application) to resume the shell?

Actually I write a single-tasking os because I want to have a really minimal and low memory consuming version of my main OS, Agola. Because I have a 80386 PC with 4 MiB of RAM. (Only 3 MiB is usable) Structures of paging, page tables and tasks takes really many space, so I can't run Agola in that PC. Then I wanted to write a low memory consuming, single tasked and really simple version of Agola, called MAgola.

Thanks in advance

Re: _exit syscall in single-tasking?

Posted: Mon May 22, 2017 9:46 am
by mallard
In MS-DOS, it goes something like this:

Program issues a system call (INT 21h function 4Bh) to launch another program.

DOS loads the new program, allocates a new stack and jumps to the entry point (note: no IRET).

When the second program terminates, DOS frees its resources, sets the stack pointer back to the previous program's value and IRETs, resuming the application.

Basically, all you need to keep hold of is each program's stack pointer.

The alternative way of doing a "single-tasking" OS, as used by (very) early versions of UNIX and MacOS, is to only ever have one program in memory and re-load a specific program (i.e. the shell) each time a program ends.