Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> This model has always been a terrible idea.

I disagree. It's an amazing idea. It allows me to write freestanding programs without any C libraries. It allows compilers to have Linux system call builtins that directly generate the calling convention. I created an entire lisp interpreter with nothing but Linux system calls, completely freestanding.

I've written a sort of manifesto around this:

https://www.matheusmoreira.com/articles/linux-system-calls

> If I were Linus

Good thing you aren't.

As a kernel, Linux is completely independent from its user space. The instruction set is the correct abstraction for the system call entry point. There should be no "required C libraries". User space should be free to reinvent everything in Rust if it wants.

There are various kernel mechanisms for system call interception if that's what you want. Tools like strace work just fine on my lisp interpreter, so libc is clearly not needed.

LD_PRELOAD is a GNU ld feature. The linker is the exact sort of user space component that's supposed to be completely replaceable. None of this is any of Linux's business.

Use of the vDSO is not even mandatory. All system calls in the vDSO are also available via the kernel entry point. The vDSO is just an optimization for frequently called system calls like gettimeofday. Forcing all programs to use the vDSO would force them all to not only implement the ELF spec but also to implement a small ELF linker. This is a significant blow if you want to create minimal freestanding Linux programs.



> It allows me to write freestanding programs without any C libraries.

KERNEL32.dll is not a C library (for once, its exported functions don't even use any of the default C calling conventions on x86).

> I created an entire lisp interpreter with nothing but Linux system calls, completely freestanding.

"Freestanding", as in "standing on top of an OS but nothing else"? Then using the OS-provided shared object that is the documented interface between the userspace and the kernel doesn't violate your free stand.

I mean, I too had written small interpreters that had only LoadLibraryW/GetProcAddress from kernel32.dll as their imports and nothing else.

> The instruction set is the correct abstraction for the system call entry point.

Why? A function call seems a much more appropriate abstraction for the system call entry point.

> There should be no "required C libraries".

There is no required C library on Windows, yet it doesn't use direct system calls.

> Forcing all programs to use the vDSO would force them all to not only implement the ELF spec but also to implement a small ELF linker.

Not really. Neither Windows nor UEFI require you to reimplement any linking functionality. The OS can simply give your program a pointer to a table of function pointers at your entry point... which it already can do, see the aux vector on Linux.


> "Freestanding", as in "standing on top of an OS but nothing else"?

Freestanding as in freestanding C.

> Then using the OS-provided shared object that is the documented interface between the userspace and the kernel doesn't violate your free stand.

Correct. I'm just saying it shouldn't be required.

> I mean, I too had written small interpreters that had only LoadLibraryW/GetProcAddress from kernel32.dll as their imports and nothing else.

And where are LoadLibraryW and GetProcAddress coming from? What if you had to implement those functions yourself?

> A function call seems a much more appropriate abstraction for the system call entry point.

The system call entry point is essentially its own calling convention. It pretty much is a function call. The function just happens to be identified by a stable number rather than function address.

> The OS can simply give your program a pointer to a table of function pointers at your entry point

It's not "a table of function pointers", it's a complete ELF object which you have to parse and resolve symbols from. That's a lot more work than putting the system call number and arguments in specific registers, executing one instruction and retrieving the return value from a specific register.


> I'm just saying it shouldn't be required.

I'm still not entirely sure why you want to use instructions from the privilleged subset of your ISA instead of plain old "call fun_addr".

> And where are LoadLibraryW and GetProcAddress coming from?

They're provided by the OS. Their addresses are patched into your executable's image during the loading. It's a very ancient technology, one of the very first software technologies invented, in fact — predates FORTRAN.

> What if you had to implement those functions yourself?

What if you had to implement exec(2) yourself? As a matter of fact, why is exec even provided as a syscall? Almost all of it (except for locking the text segment IIRC) can be done in the user space, including the parsing of the program headers and relocating stuff. Which, again, I've done once and I appreciate the OS giving it to me already implemented.

> The function just happens to be identified by a stable number rather than function address.

Or you can identify it as a stable offset into a large table of function addresses; or even as a stable character string!

    intptr_t fd = invoke_ffi("kernel32.dll!CreateFileW", fn, GENERIC_READ | GENERIC_WRITE, etc.);
    if (fd <= 0) {
        unsigned err = invoke_ffi("kernel32.dll!GetLastError", fn);
        invoke_ffi("kernel32.dll!ExitProcess", err);
        unreachable();
    }
> it's a complete ELF object which you have to parse and resolve symbols from.

You don't have to parse it. And UEFI environment in fact does give your program's entry point a table of function pointers: you put the arguments into the registers, take an offset into this table of functions, load the address, and call it, with one instruction, "call"/"branch-and-link", and it will give you the return value in a specific register. No need to parse anything by yourself.

I personally think this kind of dependency injection is pretty neat; you can intercept your own syscalls by passing pointer a modified table down your call stack. Trapping "sysenter" instruction in the userspace is way harder.


> instructions from the privilleged subset of your ISA

Absolutely nothing "privileged" about the syscall instruction. Every Linux process can run that instruction without any problems whatsoever.

> They're provided by the OS.

Not on Linux.

> You don't have to parse it.

You do on Linux. Otherwise you cannot get to the vDSO's table of symbols to function pointers.

System calls are themselves a table of function pointers, indexed by the system call number rather than by symbol. The difference is the kernel resolves it so you don't have to. That's what makes it simple and easy to use.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: