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