Live data from Hacker News

The Journey Before main()

amit.prasad.me

111–120 of 145 posts

Re: The Journey Before main()

#111

Earlier quoted context omitted.

> I've often made the argument that compilers should add builtins for Linux system calls. Just emit code in the right calling convention and the system call instruction, and return the result. Even high level dynamic languages could have their JIT compilers generate this code. You can only do that, when you compile for a specific machine. In general you are compiling for some abstract notion of an OS. JITs always com…

> You can only do that, when you compile for a specific machine. You always compile for a specific machine. There is always a target instruction set architecture. It decides the calling convention used for Linux system calls. Compiler can even produce an error in case the target is not supported by Linux. > In general you are compiling for some abstract notion of an OS. This "abstract notion of an OS" boils down to t…

Specific machine meaning defined set of installed software, versions in install locations.

Abstract notion of OS meaning Debian 12. Not Linux kernel commit ####, GNU libc commit ####, dpkg commit ####, apt commit ####, Apache httpd commit #### with patch ### to ### from Debian 4 version ### and Ubuntu 21 version ###, SQLite3 with special patches ### installed in /opt/bin/foo, ... (you get the idea).

> That's the problem. Why is the Linux stuff just a bunch of footnotes in the Linux manual? It should be in the main section. The glibc specifics should be footnotes.

Because you look at the OS manual, not at the documentation of the kernel. Notes and Bugs are also not footnotes in man pages. They are pretty important and are basically the first free-form section where you can tell about the ideas, ideals and history. The first part a pretty strict, formal description of the calling semantics.

Re: The Journey Before main()

#112

Earlier quoted context omitted.

> You can only do that, when you compile for a specific machine. You always compile for a specific machine. There is always a target instruction set architecture. It decides the calling convention used for Linux system calls. Compiler can even produce an error in case the target is not supported by Linux. > In general you are compiling for some abstract notion of an OS. This "abstract notion of an OS" boils down to t…

Specific machine meaning defined set of installed software, versions in install locations. Abstract notion of OS meaning Debian 12. Not Linux kernel commit ####, GNU libc commit ####, dpkg commit ####, apt commit ####, Apache httpd commit #### with patch ### to ### from Debian 4 version ### and Ubuntu 21 version ###, SQLite3 with special patches ### installed in /opt/bin/foo, ... (you get the idea). > That's the prob…

Let's systematize this.

Compilers build for target triples such as x86_64-linux-gnu. It is of the form isa-kernel-userspace. If kernel is linux, the builtin can be used. The isa determines the code generated by the compiler, both in general and for the builtin. The userspace can be anything at all, including none. Sometimes compilers build for target quadruples which also include a vendor, and that information is also irrelevant.

Re: The Journey Before main()

#113
post #23

Earlier quoted context omitted.

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/

Almost freestanding. It still requires you to link against kernel32 and use the functions it provides. This is because issuing system calls directly to the Windows kernel is not supported. The kernel developers reserve the right to change things like system call numbers, so they can't be hardcoded into the application.

Kernel32.dll is loaded into all Windows processes by default, so you actually can have a valid, working Windows binary with 0 entries in the import table. See here[1] for a "Hello world" program written as such.

[1]: https://gist.github.com/rfl890/195307136c7216cf243f7594832f4...

Re: The Journey Before main()

#114
post #26

Earlier quoted context omitted.

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.

> 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.

I've worked on dozens of "adult" projects for 30 years, only 2 of which ever needed to run against the Win32 API, and only one of which ever ran on Windows. There's a whole world of people out there who don't care about Windows compatibility because it's usually not relevant to the work we do.

Re: The Journey Before main()

#115

Earlier quoted context omitted.

> Windows has straight up included Linux in the system. It looks like simply targeting Linux can easily result in a binary that actually does run anywhere. Kind of. But not really. WSL2 is a thing. But most code isn’t running in WSL2 so if your thing “runs on windows” but requires running in a WSL2 context then oftentimes it might as well not exist. > They'd certainly need to pay me big bucks to care about Windows su…

There is also WSL1 and Cygwin and MinGW/MSYS2. And no WSL2 is not a newer version of WSL1, they are entirely different products.

MinGW is awful. Avoid. Cygwin is honestly not really something that has come up in my career.

I don’t know why Linux people are so adamant to break their backs - and the backs of everyone around them - to try and do things TheLinuxWay. It’s weird. IMHo it’s far far far better and to take a “when in Rome” approach.

My experience is that Linux people are MUCH worse at refusing to take a When in Rome approach than the other way. The great tragedy is that the Linux way is not always the best way.

Re: The Journey Before main()

#116

Earlier quoted context omitted.

Specific machine meaning defined set of installed software, versions in install locations. Abstract notion of OS meaning Debian 12. Not Linux kernel commit ####, GNU libc commit ####, dpkg commit ####, apt commit ####, Apache httpd commit #### with patch ### to ### from Debian 4 version ### and Ubuntu 21 version ###, SQLite3 with special patches ### installed in /opt/bin/foo, ... (you get the idea). > That's the prob…

Let's systematize this. Compilers build for target triples such as x86_64-linux-gnu. It is of the form isa-kernel-userspace. If kernel is linux, the builtin can be used. The isa determines the code generated by the compiler, both in general and for the builtin. The userspace can be anything at all, including none. Sometimes compilers build for target quadruples which also include a vendor, and that information is als…

I am not sure you understand my point. Inlining libc definitions for syscalls is fine when you only care about Debian 12 commit hash ####. It will break as soon as you think your machine is running Debian 12 and you updated it, so surely it includes the latest userspace-patches. It will also break when a user uses the OS configuration to change the behaviour of some OS functionality, but your code is oblivious to that matter, because your code bypasses the OS version of libc.

Modifying the OS is fine, if this is what you want to do, but it comes with tradeoffs.

----

You wrote earlier:

> actually tried to hack a linux_system_call builtin into GCC at some point. [...] The maintainers didn't seem too convinced in the mailing list so I didn't bother rewriting it.

I am not sure what exactly this means. There is syscall(2) in the libc, if you want to do this. If you want to inline the wrappers you can pass -static to the compiler invocation.

Re: The Journey Before main()

#117

Earlier quoted context omitted.

Almost freestanding. It still requires you to link against kernel32 and use the functions it provides. This is because issuing system calls directly to the Windows kernel is not supported. The kernel developers reserve the right to change things like system call numbers, so they can't be hardcoded into the application.

> Almost freestanding. It still requires you to link against kernel32 Nitpick: the phrase “link against kernel32” feels like a Linux-ism. If you’re only calling a few function you need to load kernel32.dll and call some functions in it. But that’s a slightly different operation than linking against it. At least how I’ve always used the term link. You’re not wrong in principle. But Linux and Windows do a lot of things…

> (I think Windows does it waaay better but ymmv)

Can you elaborate on that?

Btw., I don't want to bash Windows here, I think the Windows core OS developers are (one of) the only good developers at Microsoft. The NT kernel is widely praised for its quality and the actual OS seems to be really solid. They just happen to also have lots of shitty company sections that release crappy software and bundle malware, ads and telemetry with the actual OS.

Re: The Journey Before main()

#118
post #46

Earlier quoted context omitted.

I've always wondered why there weren't more popular loaders to choose from given that on Linux loaders are user-space

There's also binfmt support, which can check a supposedly executable file against some magic and auto-launch an interpreter (like wine or java or dosemu). I looked into it for something once but in my case the magic wasn't good enough. https://www.kernel.org/doc/html/latest/admin-guide/binfmt-mi...

Its super awesome for qemu. It let's you chroot into a arm root (full of arm binaries) on you x86 machine and just run it like normal. No VM required.

Re: The Journey Before main()

#119

Earlier quoted context omitted.

There is also WSL1 and Cygwin and MinGW/MSYS2. And no WSL2 is not a newer version of WSL1, they are entirely different products.

MinGW is awful. Avoid. Cygwin is honestly not really something that has come up in my career. I don’t know why Linux people are so adamant to break their backs - and the backs of everyone around them - to try and do things TheLinuxWay. It’s weird. IMHo it’s far far far better and to take a “when in Rome” approach. My experience is that Linux people are MUCH worse at refusing to take a When in Rome approach than the o…

I found MinGW to be quite nice, but ymmv.

> to try and do things TheLinuxWay

It's not really about TheLinuxWay. It's more that Microsoft completely lacks POSIX tools at all and the compiler needs to have a complete IDE installed, which I would need a license for, and the compiler invocation also doesn't really correspond to any other compiler.

Re: The Journey Before main()

#120
For a fun example of a crash that can occur before main() even starts: https://stackoverflow.com/questions/12570374/floating-point-...

The poster was receiving a SIGFPE (floating point exception) on a C program that is simply “int main() { return 0; }”. A fun little mystery to dive into!

Post reply on HN