Are there any practical reasons for this other than no one actually cared to keep ABI synced?
The D ABI used by DMD is bespoke, and there are some problems in 64bit C ABI. LDC afaik has a half and half situation which is no good to anyone.
GDC uses whatever is the default for it's target, which is infact C ABI.
GDC and LDC C ABI may differ, ymmv depending on what you are testing this on.
Also, GDC/LDC/DMD32/DMD64 use different portions of the druntime. For instance, if you are concatenating two arrays (a[] ~= b[];) and compile the application with DMD 32bit, and linked to a druntime built by GDC then you'll get undefined references to '_d_arrayappendcT' (for GDC, this function is useless as is not portable, so we version it out)
There are some other hidden implementation details such as the magical thread local vars differ between platforms on DMD, but remain the same on GDC, etc, etc, yada, yada...