Hacker News new | past | comments | ask | show | jobs | submit login

Was going to make the same comment. And in the article they note that they have to go own to assembly to do this anyway and I find the inline assembly with Rust to be more ergonomic and safer than the assembly facilities you get with C++ (not that I’ve done that much assembly to be fair).





I agree, Rust seems a lot better for inline assembly. For C and C++, there's too much variability between compilers for what you can actually use with inline assembly. Right now, I'm desperately waiting for #[naked] to be stable[1][2]. It's not always necessary, but it's incredibly useful for a lot of low level fuckery. Until it's there, there aren't many good alternatives; you could have a custom build script that calls out to an external assembler, I suppose.

[1]: https://github.com/rust-lang/reference/pull/1689

[2]: https://github.com/rust-lang/rust/pull/134213


Can you really complain about differences between compilers, when Rust basically has ONE compiler? You would most likely have differences if there were more Rust compilers out there. I mean, at least with C++ there are choices, and you can choose to just use one compiler like clang if the differences bother you.

Well... yes. I can definitely complain about things that are a result of different philosophies or realities for a given programming environment. In fact, I'd argue the reality of using a given programming language is the only thing that actually matters; whatever is written in specs and whatever is theoretically possible is of very little interest to most developers.

The reality today is this: If I want to deploy C++ code on Windows, MSVC or possibly Clang is for sure my best choice. If I want to integrate with Linux distributions, supporting GCC is basically mandatory. And on Apple platforms, it's Clang all the way. And of course, various BSDs will either prefer GCC or Clang. (I am guessing it's mostly Clang these days. It has been a while since I have used any BSDs.)

That means that if I want to write cross-platform software for modern desktop and server operating systems, I have to keep all of this in mind.

If you couldn't complain about this, then would it be fair to go and complain about the fact that Rust has only a single compiler? I'd argue it is fair to complain that Rust only has a single compiler, and personally support having a second more-or-less complete Rust frontend. And on that note, I am looking forward to gccrs, which I hope will eventually bring Rust to some more places in addition to hopefully cutting down on the amount of Rust things that are the way they are just because rustc does them that way.


>The reality today is this: If I want to deploy C++ code on Windows, MSVC or possibly Clang is for sure my best choice. If I want to integrate with Linux distributions, supporting GCC is basically mandatory. And on Apple platforms, it's Clang all the way. And of course, various BSDs will either prefer GCC or Clang. (I am guessing it's mostly Clang these days. It has been a while since I have used any BSDs.)

Clang works everywhere: Mac, Windows, Linux, and even BSD. As a matter of fact so does GCC. You might complain about troubles linking, say, Windows-specific libraries without MSVC. But I know you'd have it just as bad or worse trying to link Rust code to those same libraries.

>If you couldn't complain about this, then would it be fair to go and complain about the fact that Rust has only a single compiler?

It depends on which of the several advantages of multiple compilers you actually care about. Some make faster output, some are more hackable, some have better licenses (which is subjective), and some have better commercial product support.

>And on that note, I am looking forward to gccrs, which I hope will eventually bring Rust to some more places in addition to hopefully cutting down on the amount of Rust things that are the way they are just because rustc does them that way.

So you're saying that soon you'll be able to complain about inconsistencies between Rust compilers too, lol...


> Clang works everywhere: Mac, Windows, Linux, and even BSD. As a matter of fact so does GCC. You might complain about troubles linking, say, Windows-specific libraries without MSVC. But I know you'd have it just as bad or worse trying to link Rust code to those same libraries.

OK, fine, so if you limit your code to Clang, you can use the GCC asm syntax. Now it is possible to do inline asm everywhere that Clang supports. It is still the crummy GCC inline asm syntax, which has pretty poor ergonomics compared to Rust.

I wouldn't ever do this, but it can be done. The tradeoff for a relatively bad inline asm syntax doesn't seem worth it, versus just using some external assembler.

> It depends on which of the several advantages of multiple compilers you actually care about. Some make faster output, some are more hackable, some have better licenses (which is subjective), and some have better commercial product support.

Sure.

> So you're saying that soon you'll be able to complain about inconsistencies between Rust compilers too, lol...

The problem with C++ is that there isn't a standard for inline assembler and never will be.

Here is the Rust standard for inline assembler:

https://doc.rust-lang.org/reference/inline-assembly.html

If gccrs implements it, it will work just as well. I'm sure there will be some inconsistencies between the exact assembler syntax allowed across toolchains, but that's OK: it's all stuff that can be ironed out. With C and C++, it will not be ironed out. It's just going to be how it is today for all of eternity.


I thought of another reason for C++ to do this. C++ compilers allow you to customize the assembler that you use for your code. As long as that is the case, it is impossible to mandate uniform syntax. The language certainly can't standardize externally-specified code either. I bet you can't customize this in Rust.

Different assemblers, even for the same arch, support different features and instructions, and may use different syntax. So requiring uniformity is a non-starter.

>With C and C++, it will not be ironed out. It's just going to be how it is today for all of eternity.

I don't think that's true. If it is, then I guess it's a sign that the big players don't think this is an important issue. And they are the ones writing the most inline assembly, so they ought to know what is and isn't actually worth it.


> As long as that is the case, it is impossible to mandate uniform syntax. The language certainly can't standardize externally-specified code either. I bet you can't customize this in Rust. Different assemblers, even for the same arch, support different features and instructions, and may use different syntax. So requiring uniformity is a non-starter.

You’d be wrong. You can customize the build however you want by defining a build.rs file. For inline assembly I don’t see a problem with uniformity and not supporting weird shit. Weird shit should be harder if it makes the more straightforward stuff easier and less error prone.


If you customize the assembler, then I think that the inline assembly can't support uniform syntax. The syntax required by an assembler is defined by the assembler, not some language trying to inline it. The true state of things might be even more complicated, with C++ and Rust compilers choosing to parse assembly. But if they do that, it is necessarily going to interfere with using all of the features of the underlying customizable assembler.

You can use the assembler you want for standalone assembly files which is why I referenced build.rs. In inline assembly you will always be using the one assembler Rust supports on that platform.

> I don't think that's true. If it is, then I guess it's a sign that the big players don't think this is an important issue. And they are the ones writing the most inline assembly, so they ought to know what is and isn't actually worth it.

I'm not even going to attempt to go into the utter dysfunction that is the C++ standards committee, but I'll just say this: whatever I could say to convince you that it sucks, it's significantly worse than that. Trust me, the C++ standards committee refusing to address something is not a sign that there is not a problem. The reason why inline assembly will never be standardized is because that's a relatively small problem, whereas the C++ world today is full of gaping holes that the standard is utterly failing at filling. From concepts to modules, it's a shit show. The "big players" are slowly leaving. Google and Microsoft may have some of the biggest C++ codebases on Earth, and they are currently busy investing elsewhere, with Rust, Go, Carbon, and more.


>Google and Microsoft may have some of the biggest C++ codebases on Earth, and they are currently busy investing elsewhere, with Rust, Go, Carbon, and more.

I think this is overstated, and may also be construed as an attempt to monopolize and destroy what is a very successful open technology spec. I know in the case of Google especially, there were many people who got into a spat with the rest of the committee because they had a different vision of what was appropriate for the language. That is a sign that the committee is functioning correctly. It's supposed to prevent a single actor from ignorantly breaking stuff for others. You might disagree with the particular decision that was made, but I think the committee is rarely given the benefit of the doubt that it deserves.

>The reason why inline assembly will never be standardized is because that's a relatively small problem, whereas the C++ world today is full of gaping holes that the standard is utterly failing at filling. From concepts to modules, it's a shit show.

Concepts are usable today. Modules are basically usable but immature. C++ needs to be cut some slack when it comes to bleeding edge features. Other languages definitely are, and they make little in the way of compatibility commitments like C++ does. I think C++ should publish the standards after the features have been implemented for a while, but that is just a naive outsider's opinion. Every decision that could be made for this stuff has tradeoffs.

As I said elsewhere, inline assembly syntax can't be standardized without an associated assembler, which is platform-dependent and often customizable. I also think the language spec should know as little about the architecture as it can, because each one has slightly different characteristics.


> Concepts are usable today. Modules are basically usable but immature.

Concepts are usable in the sense they compile. Claiming they are usable in terms of being ergonomic and that people are willing to use them outside the stdlib is a stretch. You think it seems reasonable until you encounter Rust traits and then you wonder wtf is C++ doing.

As for modules, it’s now 5 years since standardization. How much more time does a basic feature like that take to mature? Btw, the community provided feedback to the standards committee that the spec was useless for anyone building build systems tooling around it and the committee chose to ignore that warning and this is the result.

> I know in the case of Google especially, there were many people who got into a spat with the rest of the committee because they had a different vision of what was appropriate for the language. That is a sign that the committee is functioning correctly. It's supposed to prevent a single actor from ignorantly breaking stuff for others. You might disagree with the particular decision that was made, but I think the committee is rarely given the benefit of the doubt that it deserves.

The committee was actually given a lot of benefit of the doubt after c++11 because they promised to change. They’ve squandered it.


>Concepts are usable in the sense they compile. Claiming they are usable in terms of being ergonomic and that people are willing to use them outside the stdlib is a stretch. You think it seems reasonable until you encounter Rust traits and then you wonder wtf is C++ doing.

Concepts work great. The primary purpose of them is to allow things to compile or not and to deliver readable error messages when a constraint is violated. I use them from time to time at work. I don't know about Rust traits but I do know that C++ has many useful paradigms and idioms to handle a variety of sticky situations.

>As for modules, it’s now 5 years since standardization. How much more time does a basic feature like that take to mature?

It's not as basic as you imagine, evidently. If this was any other language, the one true language authority would start building an implementation with a spec that is constantly in flux, and it could take just as long to complete. Alternatively, they'd break compatibility and shrug off the hundreds of man-years of work they generated downstream.

>Btw, the community provided feedback to the standards committee that the spec was useless for anyone building build systems tooling around it and the committee chose to ignore that warning and this is the result.

I think this means the committee sees it as someone else's job to develop the implementation details for modules. They also don't specify things such as, how shared libraries should be built or loaded, or the format of binary code.

>The committee was actually given a lot of benefit of the doubt after c++11 because they promised to change. They’ve squandered it.

They did change. We are getting regular updates and corrections now. I think the committee is more open to proposals than ever, perhaps too open. I can hardly keep up with all the cool stuff they add every couple of years.


> It's not as basic as you imagine, evidently. If this was any other language, the one true language authority would start building an implementation with a spec that is constantly in flux, and it could take just as long to complete. Alternatively, they'd break compatibility and shrug off the hundreds of man-years of work they generated downstream.

I don’t think that’s the reason. The issue isn’t modules themselves. They’re imperfect but no solution was going to be. The hostility to defining things that would make them usable resulted in them being unusable. An unusable feature is as good as one that doesn’t exist.

> They did change. We are getting regular updates and corrections now. I think the committee is more open to proposals than ever, perhaps too open. I can hardly keep up with all the cool stuff they add every couple of years.

They dick around forever and the meaningful changes are ones that aren’t really the big pain points. And when they try to solve meaningful pain points (eg ranges) they end up doing such a piss poor job that it ends up being overly complex and solving the original problem poorly. C++ as a language has utterly failed. That’s why standards body participants like Herb and Channing are trying to come ups it’s their own successor. If they thought it was solvable within the standards body they would have.


I read it as

> I agree, Rust seems a lot better for inline assembly [because there's basically only one compiler]. [Compared to] C and C++, [where] there's too much variability between compilers for what you can actually use with inline assembly


Rust's inline assembly syntax is part of the language, and in principle the same Rust source would compile on any conforming compiler (rustc, gccrs).

C/C++ doesn't have a standard syntax for inline assembly. Clang and GCC have extensions for it, with compiler-specific behavior and syntax.


I mentioned somewhere else but I might as well mention here too: there is no standard assembler that everyone uses. Each one may have a slightly different syntax, even for the same arch, and at least some C++ compilers allow you to customize the assembler used during compilation. Therefore, one would assume that inline assembly can't be uniform in general, without picking a single assembler (even assembler version) for each arch.

You're talking about the syntax of the assembly code itself. In practice small variations between assemblers isn't much of a problem for inline assembly in the same way it would be for standalone .s sources, because inline assembly rarely has implementation-specific directives and macros and such. It's not like the MASM vs NASM split.

This thread is about the compiler-specific syntax used to indicate the boundary between C and assembly and the ABI of the assembly block (register ins/outs/clobbers). Take a look at the documentation for MSVC vs GCC:

https://learn.microsoft.com/en-us/cpp/assembler/inline/asm?v...

https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html

Rust specifies the inline assembly syntax at https://doc.rust-lang.org/reference/inline-assembly.html in great detail. It's not a rustc extension, it's part of the Rust language spec.


>This thread is about the compiler-specific syntax used to indicate the boundary between C and assembly and the ABI of the assembly block (register ins/outs/clobbers).

I see... Nevertheless, this is a really weird issue to get bent out of shape over. How many people are really writing so much inline assembly and also needing to support multiple compilers with incompatible syntax?


Biggest category of libraries that need inline assembly with compiler portability are compression/decompression codecs (like the linked article) -- think of images (PNG, JPEG), audio (MP3, Opus, FLAC), video (MPEG4, H.264, AV1).

Also important is cryptography, where inline assembly provides more deterministic performance than compiler-generated instructions.

Compiler intrinsics can get you pretty far, but sometimes dropping down to assembly is the only solution. In those times, inline assembly can be more ergonomic than separate .s source files.


Exactly. It picks a single assembler:

> Currently, all supported targets follow the assembly code syntax used by LLVM’s internal assembler which usually corresponds to that of the GNU assembler (GAS)

Uniformity like that is a good thing when you need to ensure that your code compiles consistently in a supported manner forever. Swapping out assemblers isn’t helpful for inline assembly.


The quoted statement is weaker than what you're reading it as, I think. It's not a statement that emitted assembly code is guaranteed to conform to LLVM syntax, it's just noting that (1) at present, (2) for supported targets of the rustc implementation, the emitted assembly uses LLVM syntax.

Non-LLVM compilers like gccrs could support platforms that LLVM doesn't, which means the assembly syntax they emit would definitionally be non-LLVM. And even for platforms supported by both backends, gccrs might choose to emit GNU syntax.

Note also that using a non-builtin assembler is sometimes necessary for niche platforms, like if you've got a target CPU that is "MIPS plus custom SIMD instructions" or whatever.


I didn't follow up the stabilization process very closely, but I believe you're wrong. What you're describing is what used to be asm! and is now llvm_asm!. The current stable asm! syntax actually parses its own assembly instead of passing it through to the backend unchanged. This was done explicitly to allow for non-llvm backends to work, and for alternative front-ends to be able to be compatible. I saw multiple statements on this thread about alternative compilers or backends causing trouble here, and that's just not the case given the design was delayed for ages until those issues could be addressed.

Given that not all platforms that are supported by rust have currently support for asm!, I believe your last paragraph does still apply.

https://rust-lang.github.io/rfcs/2873-inline-asm.html


This sentence from the Reference is important:

  > The exact assembly code syntax is target-specific and opaque to the compiler
  > except for the way operands are substituted into the template string to form
  > the code passed to the assembler.
You can verify that rustc doesn't validate the contents of asm!() by telling it to emit the raw LLVM IR:

  % cat bogus.rs
  #![no_std]
  pub unsafe fn bogus_fn() {
   core::arch::asm!(".bogus");
   core::arch::asm!("bogus");
  }
  % rustc --crate-type=lib -C panic=abort --emit=llvm-ir -o bogus.ll bogus.rs
  % cat bogus.ll
  [...]
  ; bogus::bogus_fn
  ; Function Attrs: nounwind
  define void @_ZN5bogus8bogus_fn17h0e38c0ae539c227fE() unnamed_addr #0 {
  start:
    call void asm sideeffect alignstack ".bogus", "~{cc},~{memory}"(), !srcloc !2
    call void asm sideeffect alignstack "bogus", "~{cc},~{memory}"(), !srcloc !3
    ret void
  }
That IR is going to get passed to llvm-as and possibly onward to an external assembler, which is where the actual validation of instruction mnemonics and assembler directives happens.

---

The difference between llvm_asm!() and asm!() is in the syntax of the stuff outside of the instructions/directives -- LLVM's "~{cc},~{memory}" is what llvm_asm!() accepts more-or-less directly, and asm!() generates from backend-independent syntax.

I have an example on my blog of calling Linux syscalls via inline assembly in C, LLVM IR, and Rust. Reading it might help clarify the boundary: https://john-millikin.com/unix-syscalls#inline-assembly


Assembly by definition is platform specific. The issue isn’t that it’s the same syntax on every platform but that it’s a single standardized syntax on each platform.

I understood it that way too. I just expect that if there were more Rust compilers (a benefit which C++ has in spades) then there would most likely be many annoying differences between them as well. There isn't an ISO standard for Rust. For that matter I guess most programming languages with multiple implementations have basically the same pro and con: there's more than one way to do things.

Note that becoming an international standard (via ISO, ECMA, IETF, or whatever) isn't necessary or sufficient to avoid dialects.

If the Rust language specification is precise enough to avoid disagreements about intended behavior, then multiple compilers can be written against that spec and they can all be expected to correctly compile Rust source code to equivalent output. Even if no international standards body has signed off on it.

On the other hand, if the spec is incomplete or underspecified, then even an ANSI/ISO/IETF stamp of approval won't help bring different implementations into alignment. C/C++ has been an ISO standard for >30 years and it's still difficult to write non-trivial codebases that can compile without modification on MSVC, GCC, Clang, and ICC because the specified (= portable) part of the language is too small to use exclusively.

Or hell, look at JSON, it's tiny and been standardized by the IETF but good luck getting consistent parsing of numeric values.


You see it as a benefit, I see it as ridiculously user hostile. Porting your code to a new platform isn’t just “implement new APIs” it’s also “adjust your usage of the language to the dialect this vendor understands“. There is no benefit whatsoever to the end user and ecosystem of the language to having multiple frontends to contend with.

I’m all for multiple backends but there should be only 1 frontend. That’s why I hope gccrs remains forever a research project - it’s useful to help the Rust language people find holes in the spec but if it ever escapes the lab expect Rust to pick up C++ disease. Rust with a gcc backend is fine for when you want gcc platform support - a duplicate frontend with its own quirks serves no purpose.

I also hope Rust never moves to an ISO standard for similar reasons. As someone who has participated in an ISO committee (not language) it was a complete and utter shitshow and a giant waste of time taking forever to get simple things done.


  > I’m all for multiple backends but there should be only 1 frontend. That’s
  > why I hope gccrs remains forever a research project - it’s useful to help
  > the Rust language people find holes in the spec but if it ever escapes the
  > lab expect Rust to pick up C++ disease.
An important difference between Rust and C++ is that Rust maintains a distinction between stable and unstable features, with unstable features requiring a special toolchain and compiler pragma to use. The gccrs developers have said on record that they want to avoid creating a GNU dialect of Rust, so presumably their plan is to either have no gccrs-specific features at all, or to put such features behind an unstable #![feature] pragma.

  > Rust with a gcc backend is fine for when you want gcc platform support
  > - a duplicate frontend with its own quirks serves no purpose.
A GCC-based Rust frontend would reduce the friction needed to adopt Rust in existing large projects. The Linux kernel is a great example, many of the Linux kernel devs don't want a hard dependency on LLVM, so they're not willing to accept Rust into their part of the tree until GCC can compile it.

Dialects are created not just because of different feature sets, but also because of different interpretations of the spec / bugs. Similarly, if Rust adds a feature, it’ll take time for gccrs to port that feature - that’s a dialect or Rust becomes a negotiation of getting gccrs to adopt the feature unless you really think gccrs will follow the Rust compiler with the same set of features implemented in a version (ie tightly coupled release cycles). It’s irrelevant of the intentions - that’s going to be the outcome.

> A GCC-based Rust frontend would reduce the friction needed to adopt Rust in existing large projects. The Linux kernel is a great example, many of the Linux kernel devs don't want a hard dependency on LLVM, so they're not willing to accept Rust into their part of the tree until GCC can compile it.

How is that use case not addressed by rust_codegen_gcc? That seems like a much more useful effort for the broader community to focus on that delivers the benefits of gcc without bifurcating the frontend.


> Right now, I'm desperately waiting for #[naked] to be stable

Does the global_asm! macro suffice for your use case?


Honestly, I didn't think of that, but I can't really think of a single reason it wouldn't work. Thank you!

Name mangling.



Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: