www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Porting gdc/dmd to Hurd

reply yelninei <yelninei tutamail.com> writes:
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 
bootstrap 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.
Mar 19
next sibling parent Dejan Lekic <dejan.lekic gmail.com> writes:
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.
That is great! I hope we can help you in your endeavour. PS. Some 30 years ago I was very much interested in GNU/Hurd. Tried to become part of the community but there were countless number of insanely rude people there that made me turn my back to the project. I wonder is this still the case?
Mar 19
prev sibling next sibling parent reply HNBas <eanthol91 gmail.com> writes:
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.
Mar 20
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
The struct call/return ABI is always badly/erroneously documented, and every 
platform has to reinvent it in an undocumented, maddening way.

The way I deal with it is to write trivial C programs:
```C
struct S { int a; }
struct S test(struct S *p) { return *p; }
```

Compile it with the compiler that comes with the system, and disassemble the 
object file. Then figure out what the instructions are doing.

I've found out that asking grok or google or chatgpt for an AI description of
it 
can help a lot.
Mar 20
prev sibling parent yelninei <yelninei tutamail.com> writes:
On Friday, 20 March 2026 at 21:22:22 UTC, HNBas wrote:

 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.
Thanks a lot for the responses. I think i overlooked/missed a lot of linux cases when I initially did this. I found the i686 linux struct case in target.d and adding hurd to that seems to work. then i also found lot more unhandled cases for the os. Almost all non windows dmd tests now pass on i686 (he remaining failures seem expected), on x86_64 the test runner gets killed with the gc suspend signal after a while, not yet sure whats up with that. there are still some issues with druntime which i think is because CRuntime_Glibc is used for linux+glibc in several places. I also already found a lot of things that are not needed anymore/can be simplified significantly as some of my druntime changes are initially against gdc-11.
Mar 21
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/19/2026 9:41 AM, yelninei wrote:
 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.
Pretty much everyone who has tried to wrangle it has given up on it, which baffles me because it is trivially obvious to the most casual observer. Anyhow, feel free to ask questions about it!
Mar 20