←back to thread

Ubuntu on Windows

(blog.dustinkirkland.com)
2049 points bpierre | 5 comments | | HN request time: 0.413s | source
Show context
zymhan ◴[] No.11390932[source]
"Linux geeks can think of it sort of the inverse of "wine" -- Ubuntu binaries running natively in Windows. Microsoft calls it their "Windows Subsystem for Linux"."

I find it amazing that you can have such a functional Ubuntu environment by translating system calls. Microsoft does have the advantage of Linux being open-source I suppose, while the Wine project had to reverse engineer DLLs. Or have you supply them on your own.

replies(9): >>11391001 #>>11391011 #>>11391074 #>>11391084 #>>11391105 #>>11391166 #>>11391290 #>>11391798 #>>11391866 #
1. david-given ◴[] No.11391798[source]
So, uh. I did this! Crudely. In 2010.

http://cowlark.com/lbw/

It's a Linux syscall translator for Windows. It works well enough to run a Debian userland, although it's got so many holes and rough edges that I would never, ever, ever suggest using it for anything other than a stunt.

It uses Interix to do most of the heavy lifting, so all LBW does is to translate from Linux syscalls to Interix syscalls; so we get a Unix filesystem and user permissions and sockets and fork etc for free. (Interix was great. I'm glad they're bringing it back from the dead.) Unfortunately not all the system calls directly map onto each other; so Interix has a native fork(), but Linux emulates with clone(). I couldn't make threads work.

A few of the biggest problems were:

- the Windows page size is 64kB; the Linux page size is 4kB. The ld.so loader will try to map two bits of executable within the same 64kB boundary, and, of course, this doesn't work on Windows. I crudely hack around it by allocating pages of RAM and copying things. Write-back mapping only works at all if the application lets mmap() pick the address.

- very very very different register usage. glibc on Linux uses gs as a 'pointer' to the current thread's private data area, via a special syscall. Windows resets gs to 0 on every interrupt! I crudely hack around this by intercepting null pointer dereferences, looking at the instruction to see if it was gs, and then reloading it with the right value.

- even then, that syscall sets gs to point at a GTD segment with a size of 2^32; this wraps round the entire address space, which allows very large offsets in gs to be treated as negative numbers. Windows doesn't let you create GTD segments. It only allows LTD segments, and it caps the segment limit to the end of the user address space, so this trick won't work. I crudely hack around this by intercepting segmentation violations, looking at the instruction to see it it's a [gs+negative number] dereference, and then binary patching the executable to use a different instruction.

- glibc is horrible and undocumented. There's a big pile of key-value strings pushed onto the stack above the environment when the process is initialised, containing various magic numbers. ld.so will just crash if you get this wrong. I spent a lot of time reverse engineering the ld.so source code to figure out what these were and how to set them up.

It was all vile and horrible, but it worked surprisingly well (i.e., it worked, which was surprising).

Using the NT kernel's personality system to implement Linux syscalls natively is totally the right thing to do; that's obviously what they're doing here.

I would love to know about the internal Microsoft politics which made releasing this possible. I wonder how long it's been brewing? I did LBW in about a month of evenings; the core logic wasn't hard. I wouldn't be at all surprised if this hasn't been floating about inside Microsoft for years.

replies(4): >>11391919 #>>11391920 #>>11393130 #>>11416892 #
2. joshumax ◴[] No.11391919[source]
I used to use your program on my XP box a while back... I told an MS exec about it and he seemed really impressed. It would be funny if they got some of the core ideas for this from LBW.
3. tropo ◴[] No.11393130[source]
That "big pile of key-value strings pushed onto the stack above the environment" is auxv. You can see it in the binary /proc/*/auxv files. It's generated by the kernel's ELF loader.
replies(1): >>11393470 #
4. david-given ◴[] No.11393470[source]
Arrgh! I wish I'd known that six years ago. It'd have made life so much easier. I was trying to figure them out from reading the source code...
5. JdeBP ◴[] No.11416892[source]
Given that Interix is not being brought back from the dead ...

* https://news.ycombinator.com/item?id=11391841

... would you agree with a call for it to be?