6 ms·
As a noob. Why do programming languages rely on libc, why not a Golang library instead? And why do programs don’t statically link to libc in general?
by baby 4y ago
As a noob. Why do programming languages rely on libc, why not a Golang library instead? And why do programs don’t statically link to libc in general?
- silisili 4y agoIn Go's case, because DNS is such a bear. Not the looking up part, but all the sources and behaviors behind where and how to lookup. IIRC they couldn't even do it natively on MacOS due to system restrictions, unsure if that's still the case.
- cpach 4y agoNative DNS lookups is possible in Go on macOS. But it seems the road to get there was not exactly smooth.
- mseepgood 4y agoIt's not difficult, and it was done like that for some time, but the macOS system call interface is not guaranteed to be stable (more like guaranteed to be unstable), so the correct thing on macOS is to go through libc (libSystem), which Go now does since 1.12.
- cpach 4y agoNot exactly rocket science perhaps, but AFAICT there was some long-running tickets related to DNS lookups on macOS.
- jen20 4y agoFor DNS specifically, this landed in Go 1.20: here is the change set [1]. A different change [2] had a similar effect of using the system facilities for certificate validation in 1.18. In general, using the custom stuff “works” (until it doesn’t!) but results in janky programs that don’t behave with respect to split tunnel DNS and so forth - very common with cross compiled programs until recently. [1]: https://go-review.googlesource.com/c/go/+/446178 https://go-review.googlesource.com/c/go/+/446178 [2]: https://go-review.googlesource.com/c/go/+/353132 https://go-review.googlesource.com/c/go/+/353132
- cpuguy83 4y agoIs dns lookup provided by the kernel on macOS? I'm pretty sure this would all be done in userspace anyway. There is no "native" way to do this unless you consider libc (or libsystem) "native". There is no kernel interface to do dnd lookups just standard userspace tooling.
- pjmlp 4y agoMost of all, convenience. Not all OSes have libc per se, only those of UNIX/POSIX origin. Secondly, on most UNIX environments, libc isn't the ISO C standard library, rather the full OS public API, static linking to it is possible (GNU libc being the exception due to how it is designed), however it limits what the binary would be able to call across OS versions if at all, e.g. the actual implementation semantics change.
- masklinn 4y ago> static linking to it is possible (GNU libc being the exception due to how it is designed) Apple does not ship a statically linkable libSystem (I don’t think they ever have), and openbsd is trying to move away from it to tie up origin verification.
- pjmlp 4y agoHence the "however..." part of my comment. Also take into consideration all the other surviving commercial UNIXes, POSIX embedded OSes and POSIX environments for mainframes and micro-computers.
- TheDong 4y agoIt depends on the operating system. On solaris, freebsd, and so on, the operating system ships the kernel and libc versions together, libc makes syscalls, and everyone else makes C ABI calls to libc. The libc ABI is in fact the only interface the kernel, on solaris bsd etc, gives you to do something like "open a file" or "make a network call". On those operating systems, the kernel syscalls may change between versions, so if you statically link libc, or if you make syscalls directly, your program may break when the OS version is upgraded. Every program is meant to use the libc ABI, which they won't break, and then internally the OS may refactor libc+the kernel syscall interface together without worrying about breaking anything. macOS is similar to this. Linux is unusual in that the libc and kernel implementation are maintained separately, and both keep their own stability promises, so on linux it is viable to make a pure go implementation which makes syscalls directly. Which is exactly what go has done, and why this static toolchain is possible. Most programming languages don't bother with the linux syscall ABI because they'll have to use libc for other unixes as well (like solaris etc), so they might as well do it for linux too.
- epilys 4y agoThis is the correct answer. Don't use syscalls unless you know what you're doing, obviously. Take a look at how musl and glibc POSIX calls are implemented, some have nuances you have to be aware of, and in others libc might do hidden stuff behind the curtain. Example of small nuance that can ruin your day/week: the size of syscall(2) arguments is fixed, but for some syscalls the arguments must be smaller. Hence you have to pack and aline the values properly in the registers. This example is from the syscall(2) manpage.
- deleted 4y ago[deleted]
- eru 4y agoAnd even musl has quite a few bugs where it lags behind glibc a lot. I've recently been trying to fix some of them, but so far getting traction on their mailing list is a bit slow.
- mkup 4y agoOn Linux with glibc, static linking breaks DNS resolver client: gethostbyname(3) and friends. As a workaround, you can link to musl libc, but that is only for software written in C, it does not work with C++. FreeBSD is better in this regard (their libc allows static linking without breaking DNS client, even for C++ software). However, on both OSes static linking is incompatible with dlopen(3) and dlsym(3), i.e. your application will be unable to load any .so files, so you if you link statically to libc then you must statically link to every other library. This is unlike Windows, where OS kernel API DLLs (ntdll.dll, kernel32.dll) are separated from libc DLL (msvcrt.dll if MSVC, cw3220.dll if Borland C++, mingw-something-something.dll if MinGW, IIRC there was something similar for Watcom etc), so libcs from different compilers may load simultaneously to the address space of a process (e.g. in application with third party plugins compiled against different libc, or a different version of the same vendor libc). Also on Windows OS kernel API DLLs (ntdll.dll, kernel32.dll) are always loaded to the address space of your process, even if you link to libc statically. So your application always can call LoadLibrary(), TlsAlloc() etc, and it is possible to write libc-less applications in the plain C.
- leni536 4y ago> As a workaround, you can link to musl libc, but that is only for software written in C, it does not work with C++. AFAIK you can link libc++ against musl.
- flohofwoe 4y ago> but that is only for software written in C, it does not work with C++. I have a pretty complex C++ command line tool which works just fine with MUSL and results in a distro-agnostic executable (https://github.com/floooh/sokol-tools https://github.com/floooh/sokol-tools). What potential problems should I be aware of?
- lloeki 4y agoEven in C there can be issues. the nokigiri ruby gem builds (or used to build) libxml and libxslt (which are pure C) with patches making effort in removing a couple of GNUisms. For C++ we were faced with some issues, so the process we ended up with is: - build musl, install it in some location - inject a few GCC libs and linux headers required for C runtime to have the above location be a proper sysroot for clang to use - build LLVM libc++ and a few libs (e.g libunwind) as static libs against that sysroot using clang, and inject them into the sysroot - build whatever C++ final product we want against the sysroot using clang, statically linking libc++ in - for a dynamic lib, remove " "needed" dynamic reference to libc.so in ELF. also, hide all symbols from libc++ and load with bind local so that when loaded the shared lib prefers its internal symbols (which would make it crash if it jumps to another libc++) and does not pollute the symbol namespace with its internal ones (which would make another lib crash if it jumps to the internal libc++) - for an executable binary instead of a lib, dynamic references may instead need to be altered so that it works for both It all hinges on musl being a subset of glibc, which is not entirely true either (see the musl website for differences in behaviour, which may or may not matter depending on the piece of software) See: https://wiki.musl-libc.org/functional-differences-from-glibc.html https://wiki.musl-libc.org/functional-differences-from-glibc... https://github.com/DataDog/libddwaf/blob/c6a90d39d93f04ebb5e92c6a891b3c99db018893/docker/libddwaf/README.md#portable-libddwaf-on-any-linux-26 https://github.com/DataDog/libddwaf/blob/c6a90d39d93f04ebb5e...