It's important to note that unlike Linux, NT system call numbers are not stable. That's a very good thing --- it effectively forces all system calls to go through ntdll, which can coordinate closely with userspace in interesting ways. It's as if NT's "vdso" covered all interaction with the kernel.
For example, NT has no native 32-bit ABI like Linux does. Instead, userspace translates 32-bit to 64-bit system calls, handling the switch from long and back to long mode transparently. This elegant approach is possible because applications never make system calls directly.
Note that this page doesn't show the full set of syscalls, just a subset of them (seems to be the ones ntdll calls). The Win32k stuff, for one, don't seem to be there (edit: they're on this page instead: https://j00ru.vexillium.org/syscalls/win32k/64/), let alone more obscure ones that I expect exist but that I don't know about (like WSL stuff).
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.
> 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.
Windows, 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.
The 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).
One odd bit of trivia: the Windows system call mechanism supports up to four different tables. The first two are what you'll usually see - the first is the basic kernel services, and the second is for Win32k, the graphical subsystem. The final two slots are up for grabs and historically could be used by drivers to implement custom system calls.
The system call number determines what table is used. Calls in the 0x0-0xFFF range are handled by the first table, 0x1000-0x1FFF by the second, and so on.
As far as I know, the ability to add another system call table was only ever used by the IIS web server kernel-mode component (spud.sys).
I don't doubt your interesting bit of trivia, but I couldn't find anything online about. Do you have a source for this? I would certainly love to read more about it.
Sorry if this is an dumb question I could easily find on Google (been a webdev for most of my career), buy I'm curious why some syscalls exist on Vista SP1 for example, but don't exist on the versions before and after it.
Edit: I meant SP0, not SP1, sorry. It was this SysCall: NtListTransactions
It isn't a dumb question. I believe the reason is the following:
Leading up to any Windows release, Microsoft has a whole bunch of teams working on different features. Some of those features make it into the release, other features don't make it and get cut. What sometimes happens, is that a feature makes it in, but then problems are discovered in testing, and it gets pulled out again at the last minute. When a feature is removed late in the game like that, it is desired to take the lowest risk removal mechanism as possible–one way of doing that is to actually leave the feature in the code, but leave it undocumented, and hope nobody discovers it and uses it (an approach avoided nowadays due to the risk of exploitable security bugs in the buggy API, but in the past it was more common). Another way is to leave its APIs in-place, and either stub out their implementations (to always return an error), or even hide the actual implementation behind a #define that is turned off in the shipping copy. That way, you avoid making any changes to DLL export tables, the system call table, etc., which you worry (even just out of an abundance of caution) might have some downstream negative effect, but also don't have to worry about anyone discovering the broken feature and trying to use it. Then, in the next release, you have a choice – sometimes they will fix the issues with the feature and put it back in, other times priorities have changed and the remnants of the feature (such as API stubs) get removed altogether. That is why sometimes Windows DLLs export undocumented APIs that don't do anything.
(I've never worked for Microsoft, so this is not based on any internal info, just an inference from observing how Microsoft and other vendors do things.)
gives the same number of 481 as the number of rows in that table. Though, the grep includes man-pages that don't correspond with a syscall, like intro(2). It's just a curious coincidence.
Huh. Why is this so slow? According to Chrome, it took 704 milliseconds from clicking the "show" button on "Windows XP" to displaying the results. No network calls at all. A whole 525ms of script evaluation. Modern computer, thousand row table, wouldn't expect it to take that long.
Not sure, but innerHTML seems to be taking a long time, in a call that loops over the results of getElementsByName. Given that getElementsByName doesn't return a real array, is it possible internally it's doing bookkeeping to make sure the iteration is still over the same set of nodes? Or alternatively maybe modifying innerHTML is just slow.
Not an answer exactly, but I did some work with large HTML tables for an analytics project, and I did learn browsers struggle with larger tables.
After doing a number of optimizations, our 2000 row table took 1.2 seconds for chrome to insert the elements (purely the appendChild call). That was down from around 2.6 before trimming down the HTML.
I also ask myself this question. How can anyone use an OS where the creators deliberately hide some of the documentation?
I would love to read up on windows internals, but there are no real resources out there. A few books that at first glance appears to cover it, but then just deals with the application layer and up to point-and-click.
This is why I don't use windows anymore. I don't ever again want a job where I have to debug why old program P stopped working after an update. I prefer to be able to learn stuff.
[+] [-] quotemstr|6 years ago|reply
For example, NT has no native 32-bit ABI like Linux does. Instead, userspace translates 32-bit to 64-bit system calls, handling the switch from long and back to long mode transparently. This elegant approach is possible because applications never make system calls directly.
[+] [-] pkaye|6 years ago|reply
[+] [-] rocqua|6 years ago|reply
[+] [-] mehrdadn|6 years ago|reply
[+] [-] mehrdadn|6 years ago|reply
[+] [-] monocasa|6 years ago|reply
[+] [-] ninkendo|6 years ago|reply
[+] [-] dataflow|6 years ago|reply
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.
[+] [-] kccqzy|6 years ago|reply
[+] [-] detaro|6 years ago|reply
[+] [-] dblohm7|6 years ago|reply
[+] [-] unknown|6 years ago|reply
[deleted]
[+] [-] moyix|6 years ago|reply
The system call number determines what table is used. Calls in the 0x0-0xFFF range are handled by the first table, 0x1000-0x1FFF by the second, and so on.
As far as I know, the ability to add another system call table was only ever used by the IIS web server kernel-mode component (spud.sys).
[+] [-] crusader1099|6 years ago|reply
[+] [-] pedrocx486|6 years ago|reply
Edit: I meant SP0, not SP1, sorry. It was this SysCall: NtListTransactions
[+] [-] skissane|6 years ago|reply
Leading up to any Windows release, Microsoft has a whole bunch of teams working on different features. Some of those features make it into the release, other features don't make it and get cut. What sometimes happens, is that a feature makes it in, but then problems are discovered in testing, and it gets pulled out again at the last minute. When a feature is removed late in the game like that, it is desired to take the lowest risk removal mechanism as possible–one way of doing that is to actually leave the feature in the code, but leave it undocumented, and hope nobody discovers it and uses it (an approach avoided nowadays due to the risk of exploitable security bugs in the buggy API, but in the past it was more common). Another way is to leave its APIs in-place, and either stub out their implementations (to always return an error), or even hide the actual implementation behind a #define that is turned off in the shipping copy. That way, you avoid making any changes to DLL export tables, the system call table, etc., which you worry (even just out of an abundance of caution) might have some downstream negative effect, but also don't have to worry about anyone discovering the broken feature and trying to use it. Then, in the next release, you have a choice – sometimes they will fix the issues with the feature and put it back in, other times priorities have changed and the remnants of the feature (such as API stubs) get removed altogether. That is why sometimes Windows DLLs export undocumented APIs that don't do anything.
(I've never worked for Microsoft, so this is not based on any internal info, just an inference from observing how Microsoft and other vendors do things.)
[+] [-] mehrdadn|6 years ago|reply
[+] [-] rolph|6 years ago|reply
[+] [-] jolmg|6 years ago|reply
[+] [-] october_sky|6 years ago|reply
[+] [-] kuroguro|6 years ago|reply
[+] [-] sbierwagen|6 years ago|reply
[+] [-] mehrdadn|6 years ago|reply
[+] [-] nitwit005|6 years ago|reply
After doing a number of optimizations, our 2000 row table took 1.2 seconds for chrome to insert the elements (purely the appendChild call). That was down from around 2.6 before trimming down the HTML.
[+] [-] lucb1e|6 years ago|reply
[+] [-] prolurker|6 years ago|reply
Once layout is involved even without looping to set innerHTML it becomes a lot slower.
[+] [-] bediger4000|6 years ago|reply
Why is this even news? Doesn't Microsoft document this stuff? How does anybody use a system that doesn't have this documented?
PS http://stratigery.com/nt.sekrits.html
[+] [-] shanemhansen|6 years ago|reply
[+] [-] derpherpsson|6 years ago|reply
I would love to read up on windows internals, but there are no real resources out there. A few books that at first glance appears to cover it, but then just deals with the application layer and up to point-and-click.
This is why I don't use windows anymore. I don't ever again want a job where I have to debug why old program P stopped working after an update. I prefer to be able to learn stuff.