Hacker Newsnew | past | comments | ask | show | jobs | submit | netbsdusers's commentslogin

It's rather a bit more BSD than merely having a "C API that resembles BSD" or a "BSD userland".

https://github.com/apple-oss-distributions/xnu/tree/main/bsd

You can find there the better part of a whole BSD kernel, including the fundamental datastructures like proc, tty, vnode, and user.

The point of departure is 4.4BSD-Lite2. The majority of the core of the BSD kernel carries the relevant notices for that.


Yeah, I probably went too far in saying it's just the userland, but I'll insist it's more complicated than saying it was based on 4.4BSD-Lite2. I haven't done a proper deep dive yet, but I can tell that it wasn't strictly based on the Lite2 release. Take a look at XNU 123.5's (OS X 10.0) kern/tty.c:

https://github.com/apple/darwin-xnu/blob/xnu-123.5/bsd/kern/...

Notice the SCCS version info dates the file 1/21/94. Now look at the Lite2 equivalent:

https://github.com/sergev/4.4BSD-Lite2/blob/master/usr/src/s...

The SCCS date on this file is 1/9/95, a year later. It appears the XNU copy is from Lite1 instead:

https://github.com/dspinellis/unix-history-repo/blob/BSD-4_4...

You'll also see the source has been reorganized, with e.g. the VFS source being regrouped into bsd/vfs, instead of being left in bsd/kern. This coincidentally mirrors how OSF/1 was organized (no other source relation though, just an interesting observation):

https://github.com/Arquivotheca/OSF1/tree/OSC200/src/kernel/...

For that matter, compare the the differences between vfs_bio.c in XNU:

https://github.com/apple-oss-distributions/xnu/blob/rel/xnu-...

With Lite2's, where most function bodies have been replaced with the comment "Body deleted.", presumably due to use of encumbered code:

https://github.com/sergev/4.4BSD-Lite2/blob/master/usr/src/s...

This file had to be reimplemented by all of the BSDs. In this case, this version appears distinct from the FreeBSD and NetBSD versions I can find.

If you grep around for the `NeXT` ifndef/ifdefs in XNU, too, you'll see some code of which some appears to have been copied/adapted from the NeXT source tree, itself derived from Mach/CMU sources. (and 4.3BSD ;-)

I say all this to draw attention to the ways XNU differs from BSD, which is pretty interesting, at least to me.


No person acting in good faith can argue that having similarities to 4.3BSD-Lite1 or 4.3BSD-Reno (the basis for OSF/1) make something less of a BSD.

These are not ways it "differs from BSD." These are ways it is identical to BSD.


https://github.com/apple-oss-distributions/xnu/tree

You'll find there's a great deal left. Have a look at all the fundamental datastructures (proc, vnode, tty, file to name a few) for a starting point.


The pushback is motivated by the interests of the petty-bourgeois class, and those are a larger proportion of the former.


Imagine being a Marxist and not respecting the craft and labor required for art production. Couldn't be me.


I find it interesting that this fulfills some of Dennis Ritchie's goals for what became the STREAMS framework for byte-oriented I/O:

> I decided, with regret, that each processing module could not act as an independent process with its own call record. The numbers seemed against it: on large systems it is necessary to allow for as many as 1000 queues, and I saw no good way to run this many processes without consuming inordinate amounts of storage. As a result, stream server procedures are not allowed to block awaiting data, but instead must return after saving necessary status information explicitly. The contortions required in the code are seldom serious in practice, but the beauty of the scheme would increase if servers could be written as a simple read-write loop in the true coroutine style.

The power of that framework was exactly that it didn't need independent processes. It avoided considerable overhead that way. The cost was that you had to write coroutines by hand, and at a certain point that becomes very difficult to code. With a language that facilitates stackless coroutines, you can get much of the strengths of an architecture like STREAMS while not having to write contorted code.


> Linux won specifically because the GPL forced the "greedy" actors to collaborate.

How do we know that? It seems to me that a greater factor in the success of Linux was the idealism and community. It was about freedom. Linux was the "Revolution OS" and the hacker community couldn't but fall in love with Linux and its community that embodied their ideals. They contributed to it and they founded new kinds of firms that (at least when they began) committed themselves to respect those principles.

I realise the memory of Linux's roots in hacker culture is fading away fast but I really do think this might have been the key factor in Linux's growth. It reached a critical mass that way.

I'm quite certain of the fact that this was more important anyway than the fact that, for instance, Linksys had to (eventually! they didn't at first) release the source code to their modifications to the Linux kernel to run on the WRT54G. I don't think things like that played much of a role at all.

Linksys were certainly kind enough to permit people to flash their own firmware to that router, and that helped grow Linux in that area. They even released a special WRT54GL edition to facilitate custom firmware. But they could just as easily have Tivoised it (something that the Linux licence does not forbid) and that would've been the end of the story.


We can't really prove it but I noticed a lot of people worked on BSD for a few years, got poached by Sun/NeXT/BSDI/NetApp, then mostly stopped contributing to open source. Meanwhile early Linux devs continued contributing to Linux for decades.


Just about everything of worth in operating systems (and in software in general) was already invented in those decades.


If it's about "prettier code" then I think a number one candidate would be making bitfields more viable for use. It could make driver code much cleaner and safer.

Windows is only targeting little-endian systems which makes life easier (and in any case they trust MSVC to do the right thing) so Windows drivers make much use of them (just look at the driver samples on Microsoft's GitHub page.)

Linux is a little afraid to rely on GCC/Clang doing the right thing and in any case bitfields are underpowered for a system which targets multiple endians. So Linux uses systems of macros instead for dealing with what Windows C uses bitfields. The usual pattern is a system of macros for shifting and masking. This is considerably uglier and easier to make a mess of. It would be a real improvement in quality-of-life if this were not so.

You can also look at Managarm (which benefits from C++ here) for another approach to making this less fraught: https://github.com/managarm/managarm/blob/a698f585e14c0183df...


The c standard doesn't provide necessary guarantees around bitfield packing and ordering. I only work on little endian systems and we still avoid it.


struct packing also isn't guaranteed by the C standard, everything around that is implementation defined, as it is with bitfield packing. __attribute__((packed)) is however implemented in any sensible C compiler implementation, and things around structure layout and memory layout of data types are specified in the compiler's manual. C would be useless without those implementation-specified guarantees, because most of the appeal of C for low-level-programming comes from the ease of deserialisation through something like

char * input = receive_data();

struct deserialized * decoded = (struct deserialized *)input; // zero cost deserialization

Of course this can only work if an implementation tells you exactly what the memory layout of 'struct deserialized' and all the data types in it are.

Btw, ordering is somewhat more defined than packing, in that the usual forward/reverse/little/big-endian shenanigans are OK. But relative ordering of each field is always preserved by the C standard.


The C standard doesn't guarantee much of anything. Windows and its drivers are using bitfields anyway because they trust MSVC to do the right thing.


Doesn't Linux make similar demands of the compiler, just not for bitfields? And I seem to recall Linus having some choice words for the C Standard's tendency over the years to expand the domain of undefined behavior. I don't think the Linux devs have much patience for C thinking it can weasel out of doing what it's told due to some small print in the Standard.


Does anyone big endian anymore?


PowerPC "supports" both, but I believe it's typically run in big endian mode. Same with MIPS AFAIK.

(Mini rant: CPU people seem to think that you can avoid endianness issues by just supporting both little and big endian, not realizing the mess they're creating higher up the stack. The OS's ABI needs to be either big endian or little endian. Switchable endianness at runtime solves nothing and causes a horrendous mess.)


You could actually support both at runtime with both ABIs being available. This is done routinely on x86_64 with x86 ABI for compatibility (both sets of system libraries are installed), for a while I used to run 3 ABIs (including x32 - the 64bit with short pointers) for memory savings with interpreted languages.

IRIX iirc supported all 4 variants of MIPS; HP-UX did something weird too! I’d say for some computations one or the other endianness is preferred and can be switched at runtime.

Back in the day it also saved on a lot of network stack overheads - the kernel can switch endianness at will, and did so.


Are you advocating that Linux systems on PowerPC should have two variants of every single shared library, one using the big endian ABI for big endian programs and one using the little endian ABI for little endian programs?

Because that's how 32-bit x86 support is handled. There are two variants of every library. These days, Linux distros don't even provide 32-bit libraries by default, and Ubuntu has even moved to remove most of the 32-bit libraries from their repositories in recent years.

Apple removed 32-bit x86 support entirely a few years back so that they didn't have to ship two copies of all libraries anymore.

What you're proposing as a way to support both little and big endian ABIs is the old status quo that the whole world has been trying (successfully) to move away from for the past decade due to its significant downsides.

And this is to say nothing of all the protocols out there which are intended for communication within one computer and therefore assume native endianness.


There are downsides. Unsure if significant vs negligible. And same in terms of “internal” protocols - that essentially goes against the modularity (and while in the past there were good reasons to get away from modularity in pursuit of performance, darn, baudline.com of 2010 works amazingly well and is still in my toolbox!)

Big advantage of the “old ways” was the cohesion of software versions within a heterogenous cluster. In a way I caught the tail end of that with phasing out of MIT Athena (which at the time was very heterogeneous on the OS and architecture side) - but the question is, well, why.

Our industry is essentially a giant loop of centralizing and decentralizing, with advantages in both, and propagation delays between “new ideas” and implementation. Nothing new, all the economy is necessarily cyclic so why not this.

I’d argue that in the era of inexpensive hardware (again) and heterogenous edge compute, being able to run a single binary across all possible systems will again be advantageous for distribution. Some of that is the good old cosmopolitan libc, some of that is just a broad failure of /all/ end-point OS (which will brood its own consequences) - Windows 11, OSX, Androids etc..


I have no idea what you're trying to say. Are the "old ways" you're referring to having multiple ABIs on one system, like 32-bit and 64-bit x86? Were software versions within a heterogenous cluster more cohesive when we had 32-bit and 64-bit on the same machine..? What?


SGI IRIX and HP-UX handled multiple ABIs from one root partition, with the dynamic linker loader using appropriate paths for various userlands.

This had the advantage that one, networked root filesystem could boot both M68K and PA-RISC, or both o32 and n64 MIPS ABIs, and I’m pretty sure this would’ve worked happily on IA64 (again, from the same FS!)

The notion of “local storage boot” was relatively new and expensive in the Unix-land; single-user computing was alien, everyone was thin-clienting in. And it was trivial to create a boot server in which 32bit and 64bit and even other-arch (!) software versions were in perfect sync.

Nothing in current Linux actually forbids that. With qemu binfmt you can easily have one host and multiple userland architectures; and it sometimes even works OK for direct kernel syscalls.

All essentially aiming for a very different world, one that still runs behind the scenes in many places. The current Linux is dominated both by the “portable single-user desktop” workloads (laptops), and by essentially servers running JIT-interpreted language fast time to market startups. Which pushed the pendulum in the direction of VMs, containerization and essentially ephemeral OS. That’s fine for the stated usecase, but there are /still/ tons of old usecases of POS terminals actually using up a console driver off a (maybe emulated) old Unix. And a viable migration path for many of those might well be multi-endian (but often indeed emulated) something.

Even early Windows NT handled multi-architecture binaries and could’ve run fat binaries! We only settled on x86 in mid 1990s!


I had to look it up, Apple has been shipping code for 2+ different ISAs simultaneously, continuously since 1994

68k+PPC 1994-2007, PPC32+PPC64 2003-2008, PPC+x86 2006-2008, x86+x64 2007-2019, x64+ARM 2021-2028(announced).


That's wild they've had to carry that extra weight throughout their entire modern era. And I was thinking they were done with it, but of course they have to support the last x64 devices like the Mac Pro.


Linus hates big endian, and has some choice words to say about switchable [1]. This incarnation of Linus is certainly my favorite :)

[1]: https://lore.kernel.org/lkml/CAHk-%3DwgYcOiFvsJzFb%2BHfB4n6W...


Linus hates introducing a ton of complexity and opportunity for bugs for no upside. Pre-emptively adding runtime endianness switching to RISC-V when there's not even market demand for it 100% falls into that category. Adding runtime endianness switching to the RISC-V ISA also falls into that category.

Supporting big endian for big-endian-only CPUs does not fall into that category.


The first line in the email that I linked is pretty unambiguous:

> Oh Christ. Is somebody seriously working on BE support in 2025?

Followed by Eric:

> And as someone who works on optimized crypto and CRC code, the arm64 big endian kernel support has always been really problematic. It's rarely tested, and code that produces incorrect outputs on arm64 big endian regularly gets committed and released. It sometimes gets fixed, but not always; currently the arm64 SM3 and SM4 code produces incorrect outputs on big endian in mainline

BE support is unambiguously best-effort (which is none in some cases).

No, the Kernel does not take BE seriously. Not sure why I have to quote from the mailing list when the URL was a significant portion of my comment text - it directly contradicts your assertion on multiple fronts.


That's about someone adding BE support to an architecture which previously doesn't have it and therefore has no need for it. If you improve BE support in the kernel in order to fix or improve something on a supported BE-only architecture, I guarantee that Linus would have no qualms about it.

BE support in ARM is poor because ARM is primarily a LE architecture and almost nobody needs ARM BE.


So the existing crypto bugs that nobody is bothered with are about _adding_ support?


Linux still supports BE for several targets, his point, I think, was that no one ises risc-v as BE except maybe in an academic setting. I don't think llvm or gcc will even target BE, so not sure how they were going to conpule those mods anyway


Linux has mostly transitioned to little endian on PowerPC. AIX remains big endian.


Oh, that's excellent news! The more little endian, the better.


you must be the guy who thought of middle endian


I hear that middle endian is ideal endainness when implementing middle-out compression.


I think the kernel remains big endian. Only userspace has a brand new little-endian ABI.


Also, Net and Open BSDs support big endian PowerPC (NetBSD supports big endian arm even)


> NetBSD supports big endian arm even

AFAIK, this is probably the easiest way to test BE on hardware (if you need that for some reason) - NetBSD on a Raspberry Pi running in BE mode is easy to use. (EDIT: Actually the more important thing is that it's cheap and easy to acquire)


What's the reason someone would willingly choose to run a big endian ARM OS?


To use big endian on real-world systems. And one of the reasons to use big endian is because diversity helps to find bugs in code. A bug that might result in a hidden off-by-one on little endian might crash on big endian.


Wouldn't that only matter if the bug has no affect on little endian?

Otherwise you don't need the other endian to confirm it?

Or are you saying to test their software before it goes out to big endian devices, which doesn't answer the question as to why someone would want to use it on those end devices?


> Wouldn't that only matter if the bug has no affect on little endian?

I don't know whether this logic applies to this specific sort of bug, but there is a long history of bugs that "don't matter" combining with other bugs to become something that matters. Therac-25 was a bug that didn't matter on the hardware it was developed for, but then the software that "worked fine" got repurposed for another hardware platform and people died. If there's an easy way to identify an entire class of bugs it seems like a good idea to do it.


Think windows only supported one machine type declared with big endian from what I can see in the docs with the PE format. https://learn.microsoft.com/en-us/windows/win32/debug/pe-for...

There may have been others in the NE format. Also pretty sure the older power pc mac 7/8 machines were big endian.


Yes. The LEON series of microprocessors is quite common in space industry. It is based on SPARC v8 and SPARC is big-endian. And also, yes, SPARC v8 is a 33 years old 32-bit architecture, in space we tend to stick to the trailing edge of technology.


Hard to replace last years model super-resolutionator with this years model when you have to go out of your way to install it. ;)


We’re stuck with big endian forever because of network byte order. There will probably always be a niche market for BE CPUs for things that do lots of packet processing in software.


Anything which is a bitstream on a slow processor BE has the advantage of being simpeler, see in order processing, anything else it does not matter due to caches and the non issue of adding a few more fets here and there depending on your preferred format and arriving format. (though for debugging hex encoded data I still prefer BE but that is just a personal preference.)


From first hand experience, swapping the endianness is a non-issue in network processing performance-wise (it is headache-wise though). When processing packets in software, the cost is dominated by the following:

- memory bandwidth limits: for each packet, you do pkt NIC -> RAM, headers RAM -> cache, process, cache -> RAM, pkt RAM -> NIC. Oh and that's assuming you're only looking at headers for e.g. routing; performing DPI will have the whole packet do RAM -> cache.

- processing limits: route lookup, ACL evaluation, checksumming, etc

- branch predictor limits: if you have enough mixed traffic, the branch predictor will be basically useless. Even performing RPS will not save you if you have enough streams

So yeah, endianness is a non-issue processing-wise. So more so that one of the most expensive operations (checksumming) can be done on a LE CPU without swapping the byte order.


Even assuming this does have a measurable performance effect for the kind of processors you run Linux on (as opposed to something like a Cortex-M), you only need to have load-big-endian and store-big-endian instructions.


Memory's cheap these days. Why not store both endiannnesses in a double-width word, and have a simple bit of hardware to swap from one to the other?


z/Processor is big endian


Some firm called CodeThink have been instigating it for RISC-V lately: https://www.codethink.co.uk/articles/risc-v-big-endian-suppo...


The idea of more big endianness in Linux wasn’t particularly welcomed by Linus Torvalds however: https://lore.kernel.org/lkml/CAHk-%3DwgYcOiFvsJzFb%2BHfB4n6W...


> Since Codethink has a history of bringing big-endian support to traditionally little-endian processor architectures

But why? This sounds like a company that should have been a dissertation.


They're a consultancy: ultimately they do things because either some company paid them to do it, or because they think it will help bring in future business.

There are definitely companies out there who want to run "wrong endian" configs -- traditionally this was "I have a big endian embedded networking device and I want to move away from a dying architecture (e.g. MIPS or PPC) but I really don't want to try to find all the places in my enormous legacy codebase where we accidentally or deliberately assumed big endian".

Personally I'm not in favour of having the niche usecase tail wag the general toolchain dog, and I think that's the sentiment behind Linus's remarks.


We just have to pray that the relevant standardization bodies recognise this for the terrible idea that it is and don't ratify it.


The funny thing is that their isn't even a standardized RISC-V BE ABI yet.


ARM does both.


There's no legal concept called "tainting". Black boxing is just a means by which you try to make yourself completely irreproachable (for if you haven't seen something, then it's outright impossible that you copied it). It obviously doesn't follow that the converse is true. If it were, musicians would not listen to other's music nor would painters look at other's paintings!


The part that they're trying to avoid is the "access" in "access and substantial similarity"

https://en.wikipedia.org/wiki/Substantial_similarity

(usual factual elements in determining the possibility of a copyright infringement in U.S. law).

I agree with you that it's possible in principle that copyright infringement would not be found even when there was evidence of access. But I think the courts would usually give the defendant a higher burden in that case. You can see in the Wikipedia article that there has been debate about whether access becomes more relevant when the similarity is greater and less relevant when the similarity is less (apparently the current Ninth Circuit standard on that is "no"?).


It's just a fiction to allow something freely copiable - pure information - to be pretended to be a commodity. If the AI firms have only a single redeeming feature, then it is that in them the copyright mafia finally has to face someone their own size, rather than driving little people to suicide, as they did to Aaron Swartz.


The void type has considerable heritage, dating back all the way to ALGOL 68, and is traditionally defined as having one member:

> The mode VOID has a single value denoted by EMPTY.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: