To Save C, We Must Save ABI

(thephd.dev)

70 points | by gurjeet 3 days ago

10 comments

  • usrnm 3 hours ago
    The famous C dilemma: we want to be as close to the machine as possible, but don't want to change anything when the machine changes
    • flohofwoe 2 minutes ago
      It really hasn't much to do with C, ABIs are defined by CPU and operating system vendors. Those ABIs usually happen to be quite 'C friendly', but that's not a requirement (e.g. the Amiga OS ABI was primarily meant to be used from handwritten assembly code, and Amiga C compilers had to adapt to those ABI rules or not be able to call into operating system DLLs).
    • pjmlp 1 hour ago
      Because contrary to urban myths, C is a normal high level language like everything else.

      The Assembly like abilities have been growing as language extensions in specific compilers, not as part of ISO C.

      Going back to K&R C, inline Assembly or intrisics were not even available, all of that required using the Assembler directly.

      • titzer 5 minutes ago
        It's not normal in any other language that constant-folding in the compiler has different behavior than running an expression on the machine.

        C exists in a nether world of being neither assembly nor high-level language.

        People only call it high level because in the 1970s, having blocks, loops, and functions was high level, compared to the SoTa machines available in the day, which were either programmed with assembler or some bespoke thing the manufacturer came up with.

      • uecker 1 hour ago
        Not every high-level language gives you byte-level access to the representation of memory objects.

        But it is also wrong to reduce a language to what is in the spec.

        • pjmlp 1 hour ago
          Many do, contrary to what many C advocates talk about.

          Apparently reducing the language to what is in the spec is only a thing when talking about C and to some extent C++.

          When other languages have compiler specific extensions beyond the spec, it is a failure in their design.

          Yet when C and C++ devs have to reach out to compiler specific extensions, it is not a design failure like it is pointed out to others, rather an advantage.

          It is also wrong to not apply the same measure when it doesn't suit the message.

          • uecker 1 hour ago
            Lot of stawman arguments.
            • embedding-shape 1 hour ago
              Wouldn't be a authentic pjmlp comment unless they shit on C/C++ and/or praise Java/.NET with a bunch of straw-men :)
              • pjmlp 1 hour ago
                How wrong you are, C++ isn't in the same league as C, Microsoft was right not wanting to keep updating their C support.

                It was already outdated by the time Borland released Turbo C++ 1.0 for MS-DOS, and only got new wind thanks to GNU FOSS and their manifest to prefer C as the main compiled language for GNU projects.

                Everywhere else outside UNIX, was going with a mix of C++ for OS frameworks, Apple, Microsoft, IBM, Be, Nokia, Epoch,....

                Naturally given the option, between C, C++ and something else I might prefer that something else, however I managed a few interesting positions exactly due to my C++ skills, and interests.

                So don't mix my preferences for C and C++ on the same basket.

                • embedding-shape 1 hour ago
                  Wouldn't trade it for anything <3 Enjoy your Tuesday mate :)

                  > So don't mix my preferences for C and C++ on the same basket.

                  That mistake is mine indeed, I'll remember. Thanks, and I hope "no harm meant" was implicit :)

            • pjmlp 1 hour ago
              Really?! That is how many in C circles, including your regular comments to my comments happen to be like.

              Two measures two weights, in C versus other systems languages.

              • uecker 57 minutes ago
                Maybe provide a concrete example instead of making vague accusations. Or rather, please not, it is not a useful discourse. A productive response to my comment would be an insightful explanation of how byte-level access to memory objects is done in other languages.
          • sylware 12 minutes ago
            "When other languages have compiler specific extensions beyond the spec, it is a failure in their design."

            This one of the failures of Linus T. with the linux kernel: he was not able to keep the assembly source code with plain and simple C code you can compile with a small and alternative C compiler (same failure for the glibc devs I think).

            I don't blame him, he is already keeping the linux ABI stable, and pulling that off is something.

        • FooBarWidget 1 hour ago
          > Not every high-level language gives you byte-level access to the representation of memory objects.

          Any code that ventures anywhere near that territory is 99% Undefined Behavior. It's almost impossible to write proper C/C++ code that isn't UB while touching byte-level representations.

          • uecker 1 hour ago
            This is certainly not true. Accessing bytes of objects is well-defined in C.
    • wren6991 1 hour ago
      Except for the basic integer types. Change those as much as possible. Hell, CHAR_BIT=12 just to keep them on their toes.

      Personal pet theory: C is portable as in "you can retarget the compiler to any machine" moreso than "your code will run on any machine".

      • trashb 49 minutes ago
        > Personal pet theory

        This is actually how c grew up. This is also one of the reasons why the spec is quite ambiguous in certain locations. C is made to be easily portable not a universal codebase for all platforms (though you can get quite close with some tricks like macros). Remember the spec allows C to run on a Unisys 1100/2200 just as well as on a pdp-11.

        I may be to embedded for this but if you want your code to handle long long as int64_t use <stdint.h>. I am of the opinion that you should always use fixed width types as portable types are a huge footgun and kind off redundant.

        Especially when you start doing a little more complex things expecting them to work exactly the same, like 128bit values on a 64bit platform.

    • tonyhart7 2 hours ago
      so what they gonna do ??
  • flohofwoe 10 minutes ago
    Should have a (2022) in the title, not that anything has changed (AFAIK), but the sky didn't fall either ;)

    In the end, OS/CPU combinations define ABIs, compiler toolchains (no matter what language) can't do much more then follow (if they want to be able to talk to the operating system at least). E.g. if one day operating systems implement stable Rust-friendly ABIs, then C compilers will have to adapt to those conventions instead.

  • aw1621107 2 hours ago
    Previous submissions with comments:

    - 2023-06-10, 64 points, 16 comments: (https://news.ycombinator.com/item?id=36249253)

    - 2022-03-13, 175 points, 129 comments: (https://news.ycombinator.com/item?id=30660528)

  • sylware 6 minutes ago
    I skimmed the article, is this guy actually advocating for planned obsolescence or did I miss something??
  • clbrmbr 26 minutes ago
    I was battling GCC… until the new guy (a smart business major) pointed out I could just compile from Lua to ASM directly. Claude was happy to write a compiler over night. :facepalm:
    • fragmede 21 minutes ago
      that sounds like a fascinating use case. why were you writing Lua in the first place?
  • jdw64 2 hours ago
    But the industry ultimately runs on compatibility, so I get why they do it. But if compatibility breaks, wouldn't hardware vendors die out? If you look at PLC and other hardware manufacturers, they're not even using modern coding. They're still running on old code. They say it's 'safe and certified code,' but in reality, it's just legacy code.

    Because in hardware, programmers, aside from researchers, are often paid much less and work in worse conditions compared to their software counterparts. At a software company, code is the product itself. But in manufacturing, software is treated as a cost attached to machines worth billions of dollars. While equipment and sensors keep getting updated and more expensive, the people connecting everything are seen as a cost cutting target. So hardware programmers generally have good job security, but their salaries aren't high. In that situation, asking them to learn something new instead of sticking with the old ways usually gets resistance, because they're not being properly compensated for that learning

    • mschuster91 2 hours ago
      > In that situation, asking them to learn something new instead of sticking with the old ways usually gets resistance, because they're not being properly compensated for that learning

      And on top of that... these things are battle tested, often running machinery that isn't just worth millions of dollars but runs goods worth orders of magnitude more. Stuff breaking because some new shiny thing has been introduced... no one bats too much an eye when Reddit's UI is missing a widget here and there because someone pushed vibecoded garbage to prod again, but a car manufacturing line? A chemical plant that needs to operate 24/7 so that nothing solidifies in pipes, wrecking the entire facility to the point you need to fully dismantle it?

      When this kind of consequences are in the air, everyone is much much more conservative, because no one wants to be left holding that bag.

      • jdw64 2 hours ago
        Exactly. You're in the same industry as me. The moment you try to change something, if the production line stops, the losses are enormous—so everyone becomes conservative. That makes it even harder to change later... It's a really difficult problem
  • creshal 16 minutes ago
    Is C even worth saving at this point? Even standards committee members can't consistently write C code that doesn't overflow and segfault.
    • dummydummy1234 13 minutes ago
      What other cross-language abi do you propose?
  • add2 1 hour ago
    COM-like C ABI saves C++
  • xyzsparetimexyz 2 hours ago
    Yeah, well, that didn't happen
  • codeflo 2 hours ago
    Thousands of words that boil down to "intmax_t isn't ABI-stable". Who knew? (Everybody.)
    • aw1621107 2 hours ago
      I think that's somewhat overly reductive. A significant portion (maybe 1/3-1/2?) of the article is devoted to describing mechanisms by which an ABI could be evolved, including a new (?) mechanism implemented in the author's Clang fork and submitted to the C committee ([0] in the blog post, currently on revision 8 [1]). Sure, it isn't a perfect solution, but as the author says:

      > at least we’ll finally have the chance to have that discussion [about breaking ABI] with our communities, rather than just being outright denied the opportunity before Day 0.

      [0]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2901.htm

      [1]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3913.htm

      • uecker 1 hour ago
        The mechanism actually does not solve the problem it claims to solve.
        • aw1621107 1 hour ago
          How so?
          • pdw 1 hour ago
            Because it imagines that no library other than libc has an ABI that depends on intmax_t.

            Suppose I have a libfoo that has a public function that takes an intmax_t parameter. Or that has a public struct with an intmax_t field. It will be compiled for a particular definition of intmax_t. If you try to link it with a program that uses a different definition, it will fail.

            The article's solution with the "MY_LIBC_NEW_CODE" define cannot work because no existing C code knows about "MY_LIBC_NEW_CODE".

            The proposed mechanism is somewhat useful to a library that wants to provide multiple incompatible implementations of a function. (But this is mostly only interesting for libc implementations that need to handle historic incompatibilities between all the various Unix specs. Other libraries can just give their new, incompatible function a new name.) It's useless if you want to make an incompatible change to a type definition.

            • aw1621107 47 minutes ago
              > Because it imagines that no library other than libc has an ABI that depends on intmax_t.

              I don't get quite the same impression. The sense I get is more that such a change would basically need to happen "bottom-up":

              > Some of [the scenarios that aren't fixed by this proposal] are just the normal dependency management issues. If you build a library on top of something else that uses one of the changed types (such as intmax_t or something else), then you can’t really upgrade until your dependents do.

              > <snip>

              > For those of us in large ecosystems who have to write plugins or play nice with other applications and system libraries, we’re generally the last to get the benefits.

              In which case the benefit of the proposal (as far as I understand) is that such bottom-up changes can occur without forcibly breaking other consumers.

          • uecker 1 hour ago
            The issue is that a programmer is allowed to declare a function on its own without including the header, but then a function aliasing feature would not be visible and does not help. But if we waived this allowance, then a simple macro would do the job as well.
            • aw1621107 58 minutes ago
              I think the most recent revision of the proposal basically says it not helping for such use cases is intentional? e.g., from Section 4.4.1. Standard Library Redeclaration [0]:

              > Thankfully, we are not particularly concerned about the ability to upgrade this [user-redeclared stdlib] function: users who are declaring Standard Library functions without including the header like this are doing this strictly as experts. They have a strong expectation of what symbol they are getting from their distribution. Transparent aliases are meant to be used for functions which rely on type definitions or structures which may change, prompting the need to provide updated global variables and updated functions without breaking old binaries.

              > <snip>

              > Therefore, we do not do anything to support or inhibit such declarations. Implementations looking to keep such declarations working from older versions of code should consider leaving those old symbols within their binary artifacts (system tables, shared/static libraries, etc.) to continue supporting such a use case; this proposal is not going to address it or the myriad of other issues around this (such as strong/weak symbols and other attributes/aliasing issues).

              To be fair, that section is talking about the stdlib specifically, but nothing jumps out to me as precluding it applying to libraries in general.

              [0]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3913.htm#d...

    • pjmlp 1 hour ago
      Not really, because many don't even know there isn't such thing as C ABI, rather the OS ABI, when the OS happens to be written in C.
      • simiones 33 minutes ago
        Even this is too simplistic. While C compilers normally use the OS ABI, there is nothing that requires them to do this, and other languages don't. Of course, when you need to call functions provided by the OS, you have to do so following the OS ABI; but calls between functions written in your own language, even in different libs, don't need to follow this same rule.