_exit syscall in single-tasking?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
Agola
Member
Member
Posts: 155
Joined: Sun Nov 20, 2016 7:26 am
Location: Somewhere

_exit syscall in single-tasking?

Post 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.
Keyboard not found!

Press F1 to run setup.
Press F2 to continue.
User avatar
dozniak
Member
Member
Posts: 723
Joined: Thu Jul 12, 2012 7:29 am
Location: Tallinn, Estonia

Re: _exit syscall in single-tasking?

Post by dozniak »

syscall_exit() should be declared [[noreturn]] and not return back to the process.. problem solved.
Learn to read.
no92
Member
Member
Posts: 307
Joined: Wed Oct 30, 2013 1:57 pm
Libera.chat IRC: no92
Location: Germany
Contact:

Re: _exit syscall in single-tasking?

Post 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?)
User avatar
Agola
Member
Member
Posts: 155
Joined: Sun Nov 20, 2016 7:26 am
Location: Somewhere

Re: _exit syscall in single-tasking?

Post 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
Keyboard not found!

Press F1 to run setup.
Press F2 to continue.
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: _exit syscall in single-tasking?

Post 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. :?
You know your OS is advanced when you stop using the Intel programming guide as a reference.
Boris
Member
Member
Posts: 145
Joined: Sat Nov 07, 2015 3:12 pm

Re: _exit syscall in single-tasking?

Post 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.
User avatar
dozniak
Member
Member
Posts: 723
Joined: Thu Jul 12, 2012 7:29 am
Location: Tallinn, Estonia

Re: _exit syscall in single-tasking?

Post 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.
Learn to read.
User avatar
Agola
Member
Member
Posts: 155
Joined: Sun Nov 20, 2016 7:26 am
Location: Somewhere

Re: _exit syscall in single-tasking?

Post 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.
Keyboard not found!

Press F1 to run setup.
Press F2 to continue.
User avatar
Agola
Member
Member
Posts: 155
Joined: Sun Nov 20, 2016 7:26 am
Location: Somewhere

Re: _exit syscall in single-tasking?

Post 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
Keyboard not found!

Press F1 to run setup.
Press F2 to continue.
mallard
Member
Member
Posts: 280
Joined: Tue May 13, 2014 3:02 am
Location: Private, UK

Re: _exit syscall in single-tasking?

Post 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.
Image
Post Reply