jart / cosmopolitan

build-once run-anywhere c library
ISC License
18.33k stars 630 forks source link

Empty auxv on OpenBSD #309

Closed jacereda closed 3 years ago

jacereda commented 3 years ago

While trying to get OpenGL running on OpenBSD I noticed auxv is empty. Why is that?

jacereda commented 3 years ago

I've noticed this comment:

https://github.com/jart/cosmopolitan/blob/226aaf354786505e05283adfd52b43b668807336/libc/sysv/systemfive.S#L195

OpenBSD does indeed use auxv, it's just the constants aren't called PT_XXX. They use instead AuxId from https://github.com/openbsd/src/blob/b996670b127aa2bbace3bf72918329136b33fbf2/sys/sys/exec_elf.h#L681

At least on 7.0 I can inpect auxv values, but I don't know if that was true on earlier versions...

jacereda commented 3 years ago

This is what auxv looks like on OpenBSD 7.0:

AUX_phdr c9c7c663040
AUX_phent 38
AUX_phnum c
AUX_pagesz 1000
AUX_base c9f40545000
AUX_flags 0
AUX_entry c9c7c664720
AUX_openbsd_timekeep c9e86bc6000
jacereda commented 3 years ago

@jart Any hint on who could be stripping the auxv info?

jart commented 3 years ago

I had a feeling this day might come. I'm going to install OpenBSD 7.0 and take a look. That header file says auxv isn't part of the ABI but that may have changed recently.

jart commented 3 years ago

OK APE binaries still appear to work fine on OpenBSD 7.0. Taking a second look at the header it might be the case that OpenBSD only passes auxiliary values to dynamic shared object executables. It'd be interesting if there was a way of obtaining those values in a normal executable, but judging by the list you shared, there doesn't appear to be anything there we need. It might be nice to have AUX_openbsd_timekeep assuming it is what I think it is, but that's something which can easily be worked around by using something like nowl().

jacereda commented 3 years ago

APE binaries work fine, but I'm having trouble loading the helper executable that prepares for dlopen.

I do need the auxv to make dlopen work, I'm getting crashes when jumping to the dynamic interpreter and I suspect this is the reason.

I also thought only dynamic executables would get auxv, but I've tried to compile a static test executable that dumps auxv values and it still dumps the auxv properly.

jacereda commented 3 years ago

@jart can we leave this open?

jacereda commented 3 years ago

I have some WIP adding the AT_xxx values for OpenBSD to consts.sh and modifying loader.c and systemfive.S to detect OpenBSD via AUX_openbsd_timekeep instead of using the empty auxv, do you want me to open a draft PR with that?

jacereda commented 3 years ago

Looks like even static executables are dynamic somehow...

#include <stdio.h>
#define _DYN_LOADER
#include <elf.h>

int
main(int argc, char* argv[], char* envp[])
{
        while(*envp++);

        for (AuxInfo * au = (AuxInfo *)envp; au->au_id; au++)
        {
#define D(x) if (au->au_id==x) printf(#x " %llx\n", au->au_v)
      D(AUX_phdr);
      D(AUX_phent);
      D(AUX_phnum);
      D(AUX_pagesz);
      D(AUX_base);
      D(AUX_flags);
      D(AUX_entry);
      D(AUX_openbsd_timekeep);
        }
}
/ssh:jacereda@localhost#2222:/home/jacereda/ #$ cc -static aux.c
cc -static aux.c
/ssh:jacereda@localhost#2222:/home/jacereda/ #$ ./a.out
./a.out
AUX_phdr 9fd3190c040
AUX_phent 38
AUX_phnum b
AUX_pagesz 1000
AUX_base 9fd3190c000
AUX_flags 0
AUX_entry 9fd31911940
AUX_openbsd_timekeep a0012776000
/ssh:jacereda@localhost#2222:/home/jacereda/ #$ ldd a.out
ldd a.out
a.out:
    Start            End              Type  Open Ref GrpRef Name
    000002dd9b03f000 000002dd9b062000 dlib  1    0   0      /home/jacereda/a.out
/ssh:jacereda@localhost#2222:/home/jacereda/ #$ 

Notice the dlib type. Maybe it has something to do with ASLR on static executables?

jart commented 3 years ago

How are you getting the auxv values?

jart commented 3 years ago

Did you get a chance to read https://github.com/jart/cosmopolitan/issues/35#issuecomment-951864818 by the way? What did you think of my suggestion? I ask because GUIs are nice to have but I'm not willing to migrate away from the executable model towards dynamic shared objects in order to have them. The only way to develop GUIs the way you want to build them is to use the tools that are provided by each individual platform, which they control, and it would be hard for us to maintain a contribution we don't have any control over.

jacereda commented 3 years ago

I read it, but I don't get the rationale. Why use the terminal when you can have a normal native window and OpenGL rendering via dlopen? Offscreen rendering will involve a readback operation, that's usually a non-optimized path in most GPUs and will also introduce additional traffic in the PCI bus.

As of now, I have tested the demo on Windows and some Linux distributions (NixOS, Ubuntu, Debian) and looks like FreeBSD should work because I've reached the point where it opens the window and creates the context, but it crashes after a few operations . Probably because I'm running through emulation.

Maybe I'll figure out some way to get it running on OpenBSD that doesn't involve moving to DSOs... I'll try to construct a fake auxv and see how it goes.

Failing that, maybe we can just wait until someone with carnal knowledge about OpenBSD puts a remedy to the situation.

As for NetBSD, I can't get the latest image running on qemu.

jacereda commented 3 years ago

The only way to develop GUIs the way you want to build them is to use the tools that are provided by each individual platform

I don't get this. I don't want to build GUIs using any tool, I think https://github.com/vurtun/nuklear https://github.com/cimgui/cimgui or https://github.com/rxi/microui are the way to go. But someone might disagree and might prefer to adapt something like https://github.com/andlabs/libui once dlopen is in place.

jart commented 3 years ago

Because Cosmopolitan doesn't support dynamic shared objects. You can read more about the problems they have in Ulrich Drepper's paper. It's incompatible with the core development model. Every platform does them differently. They can only be used if you depend on the platform's C library which means we'd need to stop using our own. If you want to link system libraries into the process address space then the recommended approach is to use the platform local tools to build a driver program and launch it as a subprocess.

jacereda commented 3 years ago

I'm not sure I explained my approach properly. What I'm doing (inspired by https://github.com/pfalcon/foreign-dlopen )

I'm aware of problems caused by having several runtimes coexisting in an application, but I think those will only affect broken APIs (like something returning malloced memory and expecting the caller to just free it without passing through the library). Am I missing something else? Something that could affect OpenGL?

jart commented 3 years ago

You know your business. If I understand correctly, you can assure us that the namespaces are disjoint. Sort of like how in Go if you want to call platform C functions you use the naming C.free(). This can work. In that case, the biggest obstacle you're likely to encounter with OpenBSD isn't auxiliary values, it's msyscall(). OpenBSD has a feature where the kernel checks the RIP provenance of SYSCALL instructions. Only one contiguous memory range is permitted and msyscall() can only be called once. On process birth, it defaults to the .text section specified by the loaded PHDR. When we load the OpenBSD C library we likely have two choices. The first is that we use //third_party/xed to rewrite its instructions so they indirect through Cosmopolitan Libc. The second is we might be able to get away with just saying msyscall(0,2**47-1) but ideally it's nice to conform to platform norms and intentions in spirit whenever possible.

jart commented 3 years ago

As for NetBSD the second time's a charm. Cosmopolitan initially didn't support it, since I failed in my first attempt to install it. Then the second time I tried, many months later, the process just worked for some reason. Still haven't figured out how to get the man pages and a working compiler installed, although I hear their way of installing things is actually very good if you take the time to grok it.