Porting gdc/dmd to Hurd
HNBas
eanthol91 at gmail.com
Fri Mar 20 21:22:22 UTC 2026
On Thursday, 19 March 2026 at 16:41:41 UTC, yelninei wrote:
> Hi everyone,
>
> Over the last couple of weeks I have been trying to make
> gdc/dmd work on GNU Hurd.
>
> This mostly involved porting druntime, wiring things up in the
> gcc/dmd build system and telling dmd about the new OS.
>
> With 3 different versions of the same patch I am now able to
> https://gamer-choice.com/ boost dmd with
>
> gdc-11 -> gdc-14 -> gdmd -> dmd-2.112 -> dmd-2.112
>
> I have not looked yet at what would be needed for ldc but I
> hope it is only minimal additional changes.
>
>
> It does not work 100% correctly yet as some dmd/phobos/druntime
> tests still segfault.
>
> One thing that I am currently a bit stuck on is the following
> which is a simplification of `runnable_cxx/cabi.d` test.
>
> It currently crashes either in the c code or when D tries to
> use the value returned from C on the 32bit Hurd variant, the
> 64bit one does not seem to have the problem.
> The same code compiled with my gdc works as expected.
>
> For the codegen i have not done anything special other than
> adding hurd to the existing linux/bsd cases
>
> ```d
> import core.stdc.stdio;
>
> struct Foo1 { char c; }
> extern (C) Foo1 ctest1();
>
> void main()
> {
> Foo1 f1 = ctest1();
> printf("%d\n", f1.c);
> assert(f1.c == 3);
> }
>
> ```
>
> where ctest1 is
>
> ``` c
> struct Foo1 { char c; };
>
> struct Foo1 ctest1()
> {
> struct Foo1 f;
>
> f.c = 3;
> return f;
> }
> ```
>
> I must admit I am a bit lost in the codegen part in dmd, if
> anyone has some hints where I should look to fix this, that
> would be great.
>
> Id love to upstream my changes but I would need to clean them
> up a bit as so far I have prioritized functionality over style,
> etc. For the same reason I dont want to link to my changes yet
> but they are public if one knows where to look.
The crash you’re seeing on 32-bit smells very much like a calling
convention / ABI mismatch for small structs returned by value.
Your example (struct Foo1 { char c; }) is exactly the kind of
case where different ABIs handle returns differently (register
vs. hidden pointer).
A few things you might want to check:
First, compare what gdc emits vs. dmd for that function. Since
gdc works, it’s a good reference for the correct ABI on
Hurd/i386. Look at the generated assembly for ctest1 and the call
site – specifically how the return value is passed back. If gdc
uses a hidden sret pointer but dmd expects a register (or vice
versa), that would explain the crash.
In dmd, the relevant logic is in the backend where struct return
conventions are decided. Files around toir.d, target.d, and the C
ABI handling are worth digging into. On x86 32-bit, there’s
usually special handling for “small structs” – often ≤ 8 bytes –
but that depends on the platform ABI. Since you added Hurd under
linux/bsd, it might be inheriting the wrong assumption.
Also worth checking: alignment and packing. A char-only struct
might still be treated differently depending on default alignment
rules. Try slightly modifying the struct (e.g. add another char
or an int) and see if behavior changes – that can help confirm
it’s an ABI classification issue.
Another quick sanity check: declare the C function with
pragma(mangle) or inspect the symbol to ensure there’s no
mismatch there, though this looks more like a return-value issue
than name mangling.
Given that 64-bit works, it further points to 32-bit System V
i386 ABI quirks. Hurd might follow a slightly different
convention than Linux there, so reusing the linux path blindly
could be the root cause.
If you narrow down how Hurd expects small structs to be returned,
you’ll likely just need to tweak the classification logic in
dmd’s backend for that target.
More information about the Digitalmars-d
mailing list