8 ms·
How do they deal with the syscall numbers being different from release to release, while still maintaining binary compatibility? From what I can tell, (in Linu
by ninkendo 7y ago
How do they deal with the syscall numbers being different from release to release, while still maintaining binary compatibility? From what I can tell, (in Linux at least) the syscall numbers are the thing that needs to stay constant for the kernel to not break user space.
- mehrdadn 7y ago> How do they deal with the syscall numbers being different from release to release, while still maintaining binary compatibility By not calling syscalls based on their numbers on Windows. That might sound crazy, but actually to me coming from Windows, calling them by ordinals is what sounds crazy. :-) You're supposed to call exported functions in shared libraries (ntdll.dll etc.) that call the syscalls for you.
- rocqua 7y agoTo be fair, that is how most of linux tends to work. With glib wrappers around syscalls. It's just that the numbers are considered part of the stable interface. Hence people can write their own wrappers. It's part of linux saying 'we don't break userspace' and the syscall numbers being how userspace talks to kernelspace.
- mehrdadn 7y agoGiven glibc isn't part of the OS, and that hence you can statically link to it, it can't be part of the stable interface. glibc isn't a thing as far as the OS is concerned. It seems to me this also means Linux is more limited in what it can do in breaking syscalls too. On Windows, if you load any shared library (including ntdll) and an exported function isn't there, the loader can produce an error for you telling you that a function you need isn't there. On Linux... you're calling the syscall directly, so there's nothing that can stand between you and the syscalls to perform a check or anything. Overall it seems to me like coding against direct syscall numbers is a disadvantage on almost every front.
- caf 7y agoSo where this affects things is when you want to take advantage of a newly-added syscall, or a newly-added feature of an existing syscall. In the second case, both systems behave the same - if your program runs on an older kernel, the function entry point exists (either the syscall or ntdll symbol) but when you call the function to request the new feature, it returns a runtime error. In the first case, Linux behaves identically to the first case - you get a runtime error (ENOSYS) - whereas Windows will produce an error at load time. Typically what is done is that whatever is wrapping the syscall falls back to an alternate implementation for older kernels, if that's possible. If it's not, the program can either continue without that feature if it wants, or fail with a message that a newer kernel is required. I don't feel that there's really a significant difference in the two approaches - wherever you draw the backwards-compatibility line you're going to have to do the same sort of work to maintain it.
- account42 7y ago> Given glibc isn't part of the OS, and that hence you can statically link to it Unless you want to use any other library on the OS, for example 3D graphics drivers which tend to have hardware-specific parts in userspace. > Overall it seems to me like coding against direct syscall numbers is a disadvantage on almost every front. Which is why noone does it unless they have a very good reason.
- mehrdadn 7y ago> Unless you want to use any other library on the OS, for example 3D graphics drivers which tend to have hardware-specific parts in userspace. Not sure what you mean regarding this and glibc. > Which is why noone does it unless they have a very good reason. I think you changed the meaning of my sentence to be able to make this reply. I was referring to what Linux does re: syscalls vs. library exports, not hard-coding syscall numbers in the source code.
- asveikau 7y agoNitpick: glibc is the GNU C library and wraps syscalls, among other things. glib is a bunch of cross platform interfaces and data structures that grew out of Gtk+.
- ninkendo 7y agoSo that means ntdll.dll and family can never be statically linked? I guess that makes sense if the only responsibility of the dll is to expose syscalls, but does ntdll expose any other functionality? Functionality that may want to be overridden by a different implementation, etc? In the Linux world, since syscalls are exposed by libc, other non-C runtimes (for example, Go) end up needing to make system calls on their own without the libc wrappers. Is such a system just not a thing in Windows?
- slovenlyrobot 7y agoIt's exactly the same deal on OS X. There is no stable system call interface that is not the C library, and it's one of the main reasons they don't allow static linking there either
- mehrdadn 7y ago> In the Linux world, since syscalls are exposed by libc, other non-C runtimes (for example, Go) end up needing to make system calls on their own without the libc wrappers. Is such a system just not a thing in Windows? Yeah, it's not a thing. You just import functions from ntdll the same way you import from anything else. The OS program loader reads your program's import table and loads them for you. > does ntdll expose any other functionality? Functionality that may want to be overridden by a different implementation, etc? It exposes lots of other stuff (DLL loading, memory heap, etc.) that you may want to do differently, but you can hook those at runtime if you really want to. It's not as convenient as just linking another library, but on the other hand, it makes it easier to replace them at runtime instead of at compile-time -- say, if you want a shared library to override a syscall.
- jcranmer 7y ago> In the Linux world, since syscalls are exposed by libc, other non-C runtimes (for example, Go) end up needing to make system calls on their own without the libc wrappers. Is such a system just not a thing in Windows? Linux is pretty much the only operating system that considers the actual system call ABI to be stable. The BSDs and OS X all want you to use the platform libc instead to access system calls, while Windows uses kernel32.dll et al. as its stable interface.
- asveikau 7y agoNtdll being the de facto syscall abi is the right answer. But ntdll is also technically subject to change, much of it not publicly documented by Microsoft. So typically a third party application calls into things like kernel32 or advapi (though Win7 and later split those into different DLLs internally) which wraps ntdll which does the actual ordinal calls. But generally speaking, yeah, the stable interfaces are the C ones, exposed through system DLLs. Linux is unique in developing libc and kernel separately and the division between the two as a public abi boundary.
- mehrdadn 7y agoI mean, you could say anything is subject to change. The "documented" <-> "stable" mapping isn't a bijection. CreateFileTransacted was documented for kernel32 but that didn't stop it from being claimed as deprecated. And CallNtPowerInformation was documented and yet some of it simply doesn't work anymore. Also, Microsoft didn't necessarily document everything, but they did provide .lib files (and often headers) even for "undocumented" APIs in these libraries. Breaking these APIs would break programs they previously provided SDKs for. The reality is, so many third-party applications depend directly on ntdll APIs (even Chrome) and some of them literally cannot work with kernel32 stuff (boot-time partition managers, for one), so as far as I'm concerned, it's about as much set in stone as any library could be.
- asveikau 7y agoYeah. Direct dependence on ntdll occurs in the wild and it would break stuff to change it. It can also break MS's own code and potentially create massive engineering hurdles for them that are completely unnecessary. But they have always warned people in documentation that they don't consider it a stable interface to the same extent as Win32. In my experience a lot of the NT APIs are nicer, better thought out, more direct.
- KyleJ61782 7y agoUsing the NTDLL calls breaks stuff because NTDLL doesn't understand anything about the overlaid subsystems. NT was originally designed to support multiple subsystems in addition to Win32, like the Interix (POSIX compliant) subsystem and the OS/2 subsystem I believe. I think (I could be wrong on this) that this was possible by switching the system call table depending upon which process was currently active (doable by switching the system call vector).
- masklinn 7y ago> By not calling syscalls based on their numbers on Windows. That might sound crazy Not really. Only on Linux are direct syscalls an official ABI. On most unices (e.g. solaris, BSDs, OSX) you must dynamically link and go through the platform's libc.
- earenndil 7y agoI don't know about solaris, and I know macos had kernel changes which broke go, but freebsd has a stable kernel interface and unstable userspace. (So does linux, for that matter--ever try running a program linked to a newer version of glibc?)
- account42 7y ago> So does linux, for that matter--ever try running a program linked to a newer version of glibc? That doesn't mean the interface isn't stable or at least not less stable than the kernel interface or literally any iterface for something that is still being developed. It would be nice if glibc would provide an easy way to target the ABI of an older version (which is compatible with all newer versions) but you can do that the manual way by compiling and linking against that old version.
- detaro 7y agoApplication code does not use those syscalls directly, but functions from system libraries wrapping them, which have a stable interface.
- alxlaz 7y agoOver here in Linux world we're all super thankful that the kernel community is big on interface stability and compatibility (and not just backwards), because pretty much nobody else is. Lots of folks don't realize how important that is. If the Linux kernel space were to break as often as the Linux desktop, Linux' market share on the server and in the embedded space would likely barely exceed that of TempleOS.
- dooglius 7y agoThe difference really doesn't have to do with backward compatibility (which Windows does to arguably an even greater extent than Linux) but with where the stable interface boundary is. Windows puts the boundary in ntdll, Linux puts it at syscalls.
- gmueckl 7y agoWell, the stable kernel interface matters on Linux because the user space doesn't give a damn about backwards compatibility. You might be fine if you only rely on the system libc. But every other library that you don't ship with your binary is essentially out to break your stuff. These libraries may even differ between distributions even though they have the same version numbers just because they were built using different build configurations. This is why things like the Steam Runtime exist.
- dooglius 7y agoThat has nothing to do with kernel space vs user space and everything to do with different projects having different attitudes. The comparison is to the case where Linux instead ships a special "linuxso.so" that all processes and libraries need to (dynamically) link against in order to get a stable interface.
- deleted 7y ago[deleted]
- dblohm7 7y agoThe C stubs for NT system calls are not included as part of libc. They are implemented in ntdll.dll, which is implicitly mapped into every process (except for the new picoprocesses as used by WSL).
- kccqzy 7y agoWindows, like most other operating systems, doesn't have a stable user-kernel boundary. Instead the stable interface exists at the C level in libraries used by every process. This is no different from the situation in macOS (libSystem.dylib) or the various BSDs. Linux is the outlier because Linux is just a kernel; without an integrated C library, it by necessity has to keep the syscall numbers constant. Most other operating systems are free to change syscall numbers from release to release.