Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Rust on macOS 9 (twitter.com/turbolent)
134 points by zdw on Jan 22, 2023 | hide | past | favorite | 49 comments


The title undersells it: this means that Rust can now compile to C89, by first compiling to WebAssembly and then compiling that WebAssembly to C. This addresses one of the major concerns about Rust (and LLVM, for that matter) that I see brought up again and again here: compatibility with obscure systems that only have a C89 compiler available.


by first compiling to WebAssembly and then compiling that WebAssembly to C

That's a really indirect way, and it's not clear how much efficiency is lost in the process. It's not too far from claiming that $language can be used on a microcontroller, because $language exists on Linux, and the latter can run Linux even if via extremely slow emulation: https://news.ycombinator.com/item?id=19762928

Also related: https://news.ycombinator.com/item?id=22010159


We actually have good data on this. Very little efficiency is lost in many cases - only around 14%:

https://kripken.github.io/blog/wasm/2020/07/27/wasmboxc.html

See also here, where wasm2c is the fastest wasm runtime:

https://00f.net/2023/01/04/webassembly-benchmark-2023/

There are of course cases that can be slower, like code that depends heavily on SIMD, as wasm support for SIMD is still being improved. But in general compiling to wasm as an intermediary IR and then using an optimizing compiler can lead to very fast code.


A year ago I tested JSON Link compiled to wasm and run in wasmtime and it was around 20-25%. That isn’t bad at all considering it as a cost of running on almost anything. Didn’t see it transpiled to C89, obviously wasn’t available yet, but I think wasmtime compiled it to machine native anyways.


Could you use it as a bootstrap to build the Rust compiler on the target architecture and get the 14% back?


No need. For the Rust compiler, like most modern compilers, the list of systems it can produce binaries for is independent of which system it is running on. Either the compiler supports the instruction set and executable format used on Mac OS 9, or it doesn’t. If it does, then you could cross-compile Rust code for Mac OS 9 from any other supported system – including cross-compiling the compiler itself if desired. If it doesn’t, then it doesn’t, and even if you managed to run the compiler on Mac OS 9 (through a translation layer or otherwise), it would still only be able to produce code for its supported targets.

An exception to this principle is the linker: the Rust compiler relies on an external linker, and it may happen that the standard linker for a system only runs on that system itself. This is true on modern macOS and Windows. In this case it’s impossible to cross-compile for the target normally (at least without using a nondefault linker such as LLD). But even in that case, it’s possible to separate the compile and link steps, so you could compile an object file on another system, copy the object file to the target system, and run the linker from there. That would be inconvenient but good enough for bootstrapping purposes, so a translation layer still wouldn’t really help.


> In this case it’s impossible to cross-compile for the target normally (at least without using a nondefault linker such as LLD).

For Windows targets, you can also use Wine to accomplish cross compilation from Linux with the standard linker.


I wonder: do those WASM-2-C transpilers actually "patch back" the original external function calls from the WASM imports table back into the C source (so that system API calls would be handled directly by the system's linker), or is there still a WASI-style indirection involved going through a user-provided 'system API wrapper' (e.g. what would be needed to call into a random Mac OS 9 UI function with this solution to create a UI 'Hello World' demo - can this be handled purely with Rust's FFI features?)


"only around 14%" kills me, I remember people buying new CPUs every year for definitely less improvement than that because of how critical it is


From that link, it also sounds like 14% is the best case that requires some help from the underlying OS:

"Two results are shown for WasmBoxC, representing two implementations of memory sandboxing. The first is explicit sandboxing, in which each memory load and store is explicitly verified to be within the sandboxed memory using an explicit check (that is, an if statement is done before each memory access). This has 42% overhead.

The OS-based implementation uses the “signal handler trick” that wasm VMs use. This technique reserves lots of memory around the valid range and relies on CPU hardware to give us a signal if an access is out of bounds (for more background see section 3.1.4 in Tan, 2017). That is fully safe and has the benefit of avoiding explicit bounds checks. It has just 14% overhead! However, it cannot be used everywhere (it needs signals and CPU memory protection, and only works on 64-bit systems).

There are more options in between those 14% and 42% figures. Explicit and OS-based sandboxing preserve wasm semantics perfectly, that is, a trap will happen exactly when a wasm VM would have trapped. If we are willing to relax that (but we may not want to call it wasm if we do) then we can use masking sandboxing instead (see section 3.1.3 in Tan, 2017), which is 100% portable like explicit sandboxing and also prevents any accesses outside of the sandbox, and is somewhat faster at 29% overhead. Other sandboxing improvements are possible too - almost no effort has gone into this yet."

It sounds like this last one is the most relevant to porting code to obscure platforms (which usually means embedded these days). 29% overhead for verifiably safe sandboxing is a good trade-off, but when you don't actually need that sandboxing, I wouldn't call that insignificant. Especially on hardware that's slow by modern standards to begin with.


Most of the obscure architectures people talk about are rather slow—after all, if performance were desired, then there would be a modern compiler available for them—and so code running on them isn't performance critical.


That conclusion does not follow. Often the slower architectures need the higher performance code where modern computers can afford to waste some. 8051s are ridiculously common, because they're stupidly cheap, but they're so under-powered that software performance is absolutely critical.


According to the w2c2 readme "Coremark 1.0: ~7% slower than native" so within the generated code performance sounds quite good.

What I'm curious about is how hard it is to build a library target via this method and how much overhead there is in calling the generated code. Maybe someone who knows WebAssembly has some idea? Do call parameters need to get turned into JSON and back? Can I pass in a pointer to writable memory?


'Primitive types' like integers and floats can be passed to the other side directly as function parameters without marshalling.

For memory access I can only describe how it works in the browser environment with Emscripten (for lack of experience with other WASM integrations): The WASM heap is exposed as a Javascript ArrayBuffer object (or more correctly that ArrayBuffer object is the WASM heap, created on the JS side and handed to the WASM side at startup), with per-primitive-type array views (for instance for byte access there's a global "HEAPU8: Uint8Array" object on the JS side).

Since WASM currently only has 32-bit pointers, pointers can be passed safely to the Javascript side as JS 'numbers' without loss of information. This 'number pointer' can then be used as array index to read and write data in the WASM heap from the JS side.

Don't know how it works in WASM engines outside the browser, but I suppose it's similar (e.g. a shared heap between the native side and WASM), except maybe that you can also pass 64-bit integers around without data loss.

But in no case there needs to be any JSON- or Protobuf-style 'parameter serialization' involved.

This old blog post might contain some more information: https://hacks.mozilla.org/2018/10/calls-between-javascript-a...


There's not much data in the performance section of the front-page readme of the repo, but the one bullet point there seems promising:

> Coremark 1.0: ~7% slower than native [0]

[0] https://github.com/turbolent/w2c2#performance


Adding more IRs isn't necessarily a problem. Clang goes through AST -> LLVM IR -> SelectionDAG -> MachineInstr -> assembly already.


Not to be confused with obscure Linux ports that only have GCC available. This doesn’t address the problem of making (existing, cross-platform) Rust code work on those systems, since (I assume) it doesn’t provide FFI with native code. However, rustc_codegen_gcc will save the day eventually.


I've been working for some time on getting a modern-ish (really, modern-SSL-supporting) browser running on my Mac OS 9.1 iMac G3. My initial approach has been to try to a version of Classzilla[0] with support for more modern encryption.

I wonder if I've been overthinking it. Surely, I could just compile Firefox or Chromium source to WASM, compile that with this tool, and then have a fully working browser! What could possibly go wrong?

[0] https://www.floodgap.com/software/classilla/


I had until recently an G5 PowerPC Imac I installed Linux on (Void-ppc linux) and the Linux on Powerpc community people have developped a firefox fork (Arctic Fox) which was working well but the real problem is that is was quite slow, single-core CPUS can't stand modern browsing. Blog reading was fine but anything else took more time than I was ready to wait for. I wanted to make it a no distraction machine to run vim in and read documentation but the machine maintenance was itself a distraction in the end.


Mac OS 9

Apple didn’t start calling it macOS until years after iOS was a thing and iOS was called OS X and iPhone OS first.


Actually, OS X was short for Mac OS X, where "X" was the roman numeral "10". In a way, the name never changed.


I think they didn't start calling it Mac OS until 7.5 or so. Before that it was "system 7", "system 6", etc.


You're confidently incorrect. If you weren't paying attention at the time, it's literally in the first sentence of the Wikipedia article. This isn't hard to check.

"OS X" was the official name for five years, from 2011-2016. It wasn't short for anything. The "Mac" prefix had been officially removed from it for that time.

This reminds me of when my grade school teacher kept trying to insist that my friend, named Alex, was actually named Alexander. I think he originally brought in a copy of his birth certificate to shut them up.


I disagree with Wikipedia's framing. There wasn't some sort of major rebrand in 2011, Apple just stopped writing "Mac" at the start of the name. Old-timers knew what it stood for.

It's like how "Mac" is still short for "Macintosh", even though Apple basically never uses the full name anymore.


Apple made a pretty big deal about all the rebrands. From "System" (verions 1-7), to "Mac OS" (8 and 9), to "Mac OS X" (10.0-10.7), to "OS X" (10.8-10.12), to "macOS" (10.13+).

It was clear that the OS wasn't thought of as a separate thing in the early days. The latest one looks like a typo.


Indeed, you can see between 2011 and 2012 (for example) that Apple's PR site changed from calling it "Mac OS X" to simply calling it "OS X".

2011: https://web.archive.org/web/20111130104524/http://www.apple....

2012: https://web.archive.org/web/20120222083925/http://www.apple....

Interestingly Lion was called "Mac OS X Lion" upon release[0], but then their website[1] called it "OS X Lion" predominantly.

[0] https://www.apple.com/newsroom/2011/07/20Mac-OS-X-Lion-Avail...

[1] https://web.archive.org/web/20110705041542/http://www.apple....


2012 link is the same as the 2011 link.

Actual 2012 link: https://web.archive.org/web/20121207053101/http://www.apple....


Woops, copy/paste struggles! Thanks, updated my 2012 link while I was still able to edit.


They didn't "just stop writing it" in some contexts. They started registering trademarks that explicitly didn't include it, and then they went back.

The trademark for "OS X" on its own was approved in November 2011, and then Apple started using it on its own. Their other trademark registrations (e.g. USPTO TM SN 86097345 OS X Mavericks) continued in that form, until their registration for "macOS" was approved and they changed back (e.g. USPTO TM SN 87534929 macOS High Sierra).

You can have your etymology and your opinion, but as far as Apple and the government are concerned, the fact is that the official name was just "OS X". Wikipedia is correct, and this was also the understanding among Apple fans at the time.


Thanks for the correction.

Deleted.


Your memory is incorrect. The branding sequence was System (from before I remember up to 7.5) -> Mac OS (7.6 to 9) -> Mac OS X (10.0 to ??) -> OS X (??) -> macOS (starting after 2015). Edit: Sibling comment from htimsenyawed looks right to me.


macOS was originally Mac OS X and short referenced as OS X. The official name change from Mac OS X to macOS began with release 10.12 Sierra, the previous version was called Mac OS X 10.11 El Capitan. The transition to macOS from Mac OS X occurred in 2016 as that was the year that Sierra was announced and released.


I’d just like to interject for a moment. What you’re referring to as OS X, is in fact, Mac OS X, or as I’ve recently taken to calling it, macOS.


Also, and I'm not sure if I remember that correctly, I think during "Mac OS X" times they said it is pronounced as "mac OS ten", because X is the roman numeral for 10.

Wikipedia has references about it where Apple themselves even back then used either pronunciation, though. Also a reference that says while it stands for 10 it also references the X commonly found in many Unix things because of the Unix roots of Mac OS X.


You’re missing the intermediate transition to “OS X”


It was released as "Mac OS X", and then later shortened/rebranded to just "OS X". Unless you want to argue that the etymology of "OS X" is completely unrelated to "Mac OS X" and is merely coincidentally very similar, the statement "OS X was short for Mac OS X" is correct by all but the most pedantic definition.


A rare inverted confidentally incorrect, when someone claims (incorrectly and with great confidence) that someone else is confidently incorrect.


> This reminds me of when my grade school teacher kept trying to insist that my friend, named Alex, was actually named Alexander. I think he originally brought in a copy of his birth certificate to shut them up.

This is like telling someone who is called Louis that his actual name is Hlodowig.


Um actually, OS X was a distinct branding from Mac OS X.



Here’s the startup screen from MacOS 8 [1] which came out in 1997, more than a decade before the iPhone came out.

[1] https://en.wikipedia.org/wiki/File:Mac_os_8_splash_screen.pn...


Very clearly a space there between the "Mac" and "OS".


Capital M vs lower case m. Apple loves their first letters to be lowercase.


What was the biggest difference from a consumer perspective when moving from Mac OS 9 to Mac OS X?

I was too young to remember, but do recall the Win 98/ME → XP upgrade being a huge headache, and was wondering whether people faced similar teething issues.


A lot. Much bigger interface differences than 98 to XP, many programs required "Classic" mode to run essentially a Mac OS 9 VM. Some programs like games ran like arse in Classic mode so you had to dual boot to get decent performance. Plus the first several Mac OS X versions weren't exactly quick on hardware designed with classic Mac OS in mind like the iMac G3. But it looked a lot better and wouldn't crash all the time.


Mac OS 9 and earlier were fully custom whereas Mac OS X is UNIX based on Darwin (a BSD). Some versions of OS X are fully UNIX-certified.


>Some versions of OS X are fully UNIX-certified

Everything since 10.5 Leopard (2007)

https://www.opengroup.org/openbrand/register/


Interesting. I thought I saw somewhere that Apple stopped applying macOS for some certification, but it looks like the latest versions of macOS definitely have UNIX certification.

Maybe what I saw was about POSIX certification, but it's shockingly hard to find definitive info on that online. I can find the list of UNIX-certified operating systems, but not the list of POSIX-certified operating systems, at least not from an authoritative source. The latest version of macOS is POSIX-certified but I can't tell if there were any gaps between 10.5 and now.

Maybe the info I saw was total bogus.


Does this imply I could port anything I can compile to WASM to MacOS 9 this way? Cough Go cough.




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

Search: