D as a Better C
Michael V. Franklin via Digitalmars-d-announce
digitalmars-d-announce at puremagic.com
Tue Aug 29 19:19:21 PDT 2017
On Wednesday, 30 August 2017 at 00:29:19 UTC, Parke wrote:
> But my original question was about what you (Kagamin) called
> "intermediate D". I was trying to understand what
> "intermediate D"
> is, and whether or not I could use "intermediate D" (whatever
> it is)
> to produce small(er) executables.
"Intermediate D" probably refers to not use the -betterC switch,
not linking in the official druntime, and instead implementing
the features of D required by your program yourself.
For example, the following is the most minimal "Hello World" I
can make with D that does not require the -betterC switch, and
does not use the official D runtime. Instead the runtime
features required by this program are implemented in object.d.
object.d
--------
module object;
alias immutable(char)[] string;
struct ModuleInfo { }
class Object { }
class TypeInfo
{
bool equals(in void* p1, in void* p2) const
{
return p1 == p2;
}
int compare(in void* p1, in void* p2) const
{
return _xopCmp(p1, p2);
}
}
class TypeInfo_Class : TypeInfo
{
ubyte[136] ignore;
}
alias TypeInfo_Class ClassInfo;
class TypeInfo_Struct : TypeInfo
{
ubyte[120] ignore;
}
extern (C) Object _d_newclass(const ClassInfo ci)
{
return null;
}
extern(C) void _d_throwc(Object h) { }
class Throwable { }
class Error : Throwable
{
this(string x)
{ }
}
extern(C) void _d_throwdwarf(Throwable o) { }
extern(C) void _d_dso_registry(void* data) { }
// The following code basically replaces the C runtime
//----------------------------------------------------
extern extern(C) int main(int argc, char** argv);
extern(C) void sys_exit(long arg1)
{
asm
{
mov RAX, 60;
mov RDI, arg1;
syscall;
}
}
extern(C) void _start()
{
auto ret = main(0, null);
sys_exit(ret);
}
private alias extern(C) int function(char[][] args) MainFunc;
extern (C) int _d_run_main(int argc, char **argv, MainFunc
mainFunc)
{
// ignore args for now
return mainFunc(null);
}
main.d
------
module main;
long sys_write(long arg1, in void* arg2, long arg3)
{
long result;
asm
{
mov RAX, 1;
mov RDI, arg1;
mov RSI, arg2;
mov RDX, arg3;
syscall;
}
return result;
}
void write(in string text)
{
sys_write(2, text.ptr, text.length);
}
void main()
{
write("Hello\n");
}
Building and executing
----------------------
On Linux 64-bit compile with:
$ dmd -c -fPIC -release object.d main.d -of=main.o
Link with:
$ ld main.o -o main
Report size:
$ size main
text data bss dec hex filename
1070 1872 8 2950 b86 main
Text execution:
$ ./main
Hello
If you link with:
$ ld main.o -o main --gc-sections
You end up with:
$ size main
text data bss dec hex filename
950 1688 0 2638 a4e main
This illustration does not require -betterC, but instead requires
you to implement a "minimal D runtime" specific to your program,
and the features of D that it employs. In this illustration that
"minimal D runtime" is object.d.
As you can see it is not a polished experience and gets much
worse when you start employing more features of D. This could be
improved, and in fact, with GDC you need even less useless
boilerplate in object.d and may end up with an even smaller
executable. (Maybe I'll follow up later with GDC illustration.
Right now I don't have a computer with the latest GDC installed).
If you try this experiment with LDC, you may end up with a
multi-gigabyte file and crash your PC due to
https://github.com/ldc-developers/ldc/issues/781
Hopefully we can improve the compiler/runtime implementation so
doing this kind of programming won't require so many useless
stubs, and users can implement just the features of D that they
need for their program without having to rely on the on the blunt
and heavy hand of -betterC.
Mike
More information about the Digitalmars-d-announce
mailing list