I wonder how many C projects prefer to avoid standard library, just invoking Linux syscalls directly. Much more fun to write software this way, IMO.
The Journey Before main()
21–30 of 145 posts
Re: The Journey Before main()
#22This is not how dynamic linking works on GNU/Linux. The kernel processes the program headers for the main program (mapping the PT_LOAD segments, without relocating them) and notices the PT_INTERP program interpreter (the path to the dynamic linker) among the program headers. The kernel then loads the dynamic linker in much the same way as the main program (again without relocation) and transfers control to its entry point. It's up to the dynamic linker to self-relocate, load the referenced share objects (this time using plain mmap and mprotect, the kernel ELF loader is not used for that), relocate them and the main program, and then transfer control to the main program.
The scheme is not that dissimilar to the #! shebang lines, with the dynamic linker taking the role of the script interpreter, except that ELF is a binary format.
Re: The Journey Before main()
#23I wonder how many C projects prefer to avoid standard library, just invoking Linux syscalls directly. Much more fun to write software this way, IMO.
You had me with “avoid C standard library” but lost me at “incoming Linux syscalls directly”. Windows support is a requirement, and no WSL2 doesn’t count. C standard library is pretty bad and it’d be great if not using it was a little easier and more common.
Re: The Journey Before main()
#24Earlier quoted context omitted.
You can do this in Windows too, useful if you want tiny executables that use minimum resources. I wrote this little systemwide mute utility for Windows that way, annoying to be missing some parts of the CRT but not bad, code here: https://github.com/pablocastro/minimute
I thought windows had an unstable syscall interface?
You have your usual Win32 API functions found in libraries like Kernel32, User32, and GDI32, but since after Windows XP, those don't actually make system calls. The actual system calls are found in NTDLL and Win32U. Lots of functions you can import, and they're basically one instruction long. Just SYSENTER for the native version, or a switch back to 64-bit mode for a WOW64 DLL. The names of the function always begin with Nt, like NtCreateFile. There's a corresponding Kernel mode call that starts with Zw instead, so in Kernel mode you have ZwCreateFile.
But the system call numbers used with SYSENTER are indeed reordered every time there's a major version change to Windows, so you just call into NTDLL or Win32U instead if you want to directly make a system call.
Re: The Journey Before main()
#25iirc execve maps pt_load segments from the program header, populates the aux vector on the stack, and jump straight to the ELF interpreter's entry point. Any linked objects are loaded in userspace by the elf interpreter. The kernel has no knowledge of the PLT/GOT.
Re: The Journey Before main()
#26I wonder how many C projects prefer to avoid standard library, just invoking Linux syscalls directly. Much more fun to write software this way, IMO.
You had me with “avoid C standard library” but lost me at “incoming Linux syscalls directly”. Windows support is a requirement, and no WSL2 doesn’t count. C standard library is pretty bad and it’d be great if not using it was a little easier and more common.
Re: The Journey Before main()
#27I wonder how many C projects prefer to avoid standard library, just invoking Linux syscalls directly. Much more fun to write software this way, IMO.
I generally try to stay portable, but file descriptors are just to nice, to not use them.
Re: The Journey Before main()
#28> The ELF file contains a dynamic section which tells the kernel which shared libraries to load, and another section which tells the kernel to dynamically “relocate” pointers to those functions, so everything checks out. This is not how dynamic linking works on GNU/Linux. The kernel processes the program headers for the main program (mapping the PT_LOAD segments, without relocating them) and notices the PT_INTERP pro…
Re: The Journey Before main()
#29Earlier quoted context omitted.
You had me with “avoid C standard library” but lost me at “incoming Linux syscalls directly”. Windows support is a requirement, and no WSL2 doesn’t count. C standard library is pretty bad and it’d be great if not using it was a little easier and more common.
Obviously only a requirement if you intend your software to run under windows. But if you don't, why bother. Not all software is intended to be distributed to users far and wide. Some of it is just for yourself, and some of it will only ever run on linux servers.
I’ve spent quite a lot of time dealing with code that will ever run on Linux which did not in fact only ever run on Linux!
Obviously for hobby projects anyone can do what they want. But adult projects should support Windows imho and consider Windows support from the start. Cross-platform is super easy unless you choose to make it hard.
Re: The Journey Before main()
#30Earlier quoted context omitted.
You had me with “avoid C standard library” but lost me at “incoming Linux syscalls directly”. Windows support is a requirement, and no WSL2 doesn’t count. C standard library is pretty bad and it’d be great if not using it was a little easier and more common.
You can make CRT-free Win32 programs, read this guide[1] and you're all set. I've written a couple CLI utilities which are completely CRT-free and weigh just under a few kilobytes. [1]: https://nullprogram.com/blog/2023/02/15/