dmd -betterC
Adam D. Ruppe via Digitalmars-d
digitalmars-d at puremagic.com
Wed Jun 21 19:18:55 PDT 2017
On Wednesday, 21 June 2017 at 15:37:03 UTC, Adam D. Ruppe wrote:
> we have a *working* "better C".
I applied my two PRs along with Walter's patch and now have
runtimeless D actually working.
Take a look at this:
----
// dmd still assumes these are present
// and they are in the C lib, but no without it
extern(C) void _Unwind_Resume() { asm { int 3; } }
extern(C) void __assert(bool c, in char* msg) {}
struct Foo {
int x;
char y;
Foo* next;
~this() {
printf("goodbye world %d\n", x);
}
}
enum Test {
a, b
}
extern (C) int main(char** argv, int argc) {
scope(exit) printf("cruel world\n");
try {
Foo foo;
foo.x = 10;
int[6] buffer;
int[] bar = buffer[1 .. 4];
printf("hello world %d\n", foo.x);
} finally {
printf("sweet\n");
}
//assert(argc > 4, "foo");
return 0;
}
void printf(T...)(string a, T t) {
write(a);
char[16] buffer;
foreach(arg; t)
write(intToString(arg, buffer[]));
}
char[] intToString(int i, char[] buffer) {
int pos = cast(int) buffer.length - 1;
if(i == 0) {
buffer[pos] = '0';
pos--;
}
while(pos > 0 && i) {
buffer[pos] = (i % 10) + '0';
pos--;
i /= 10;
}
return buffer[pos + 1 .. $];
}
void write(in char[] a) {
auto sptr = a.ptr;
auto slen = a.length;
size_t fd = 1;
version(D_InlineAsm_X86)
asm {
mov ECX, sptr;
mov EDX, slen;
mov EBX, fd;
mov EAX, 4; // sys_write
int 0x80;
}
else version(D_InlineAsm_X86_64)
asm {
mov RSI, sptr;
mov RDX, slen;
mov RDI, fd;
mov RAX, 1; // sys_write
syscall;
}
}
extern(C) void _start() {
size_t code = main(null, 0);
version(D_InlineAsm_X86)
asm {
mov EAX, 1; // sys_exit
mov EBX, code;
int 0x80;
}
else version(D_InlineAsm_X86_64)
asm {
mov RAX, 60; // sys_exit
mov RDI, code;
syscall;
}
}
----
# Note that the -I is not necessary if your compiler is
# actually installed; I just need it here since it is a
# hacked up compiler
src/dmd hello.d -I../druntime/import -betterC -release -c
ld hello.o -nostdlib
$ ls -lh a.out
-rwxr-xr-x 1 me users 2.5K Jun 21 22:13 a.out
$ ldd a.out
not a dynamic executable
Wow. If you remember my old minimal.d, it took about 15 lines of
stub runtime to even get it to compile.... and was still 3.3 K in
my best attempt.
Now it works - including structs with dtors (if you have my two
PRs merged) - and makes a tiny 2.5 K exe (on Linux here), with
zero dependencies. This could run on bare metal. I've done that
before, but never this simple.
* * *
What about using the C library?
---
import core.stdc.stdio;
struct Test {
int x;
int y;
this(int x, int y) {
this.x = y;
this.y = y;
printf("Constructed\n");
foo();
}
~this() {
printf("Destructed\n");
foo();
}
void foo() {
printf("Values are: %d, %d\n", x, y);
}
}
extern(C) int main() {
printf("Hello!\n");
scope(exit) printf("Bye!\n");
Test test = Test(10, 20);
test.x += 45;
test.foo();
return 0;
}
---
Look at that - looks like a reasonably useful program, with
structs, printing, members, even a destructor. How hard was it to
build?
$ src/dmd hello2.d -betterC -I../druntime/import
$ ./hello2
Hello!
Constructed
Values are: 20, 20
Values are: 65, 20
Destructed
Values are: 65, 20
Bye!
$ ls -lh hello2
-rwxr-xr-x 1 me users 11K Jun 21 22:18 hello2
$ ldd hello2
linux-vdso.so.1 (0x00007ffe4b3fc000)
libpthread.so.0 => /lib64/libpthread.so.0
(0x00007fabb78f6000)
libm.so.6 => /lib64/libm.so.6 (0x00007fabb75f3000)
librt.so.1 => /lib64/librt.so.1 (0x00007fabb73ea000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fabb71e6000)
libgcc_s.so.1 => /usr/lib64/libgcc_s.so.1
(0x00007fabb6fd0000)
libc.so.6 => /lib64/libc.so.6 (0x00007fabb6c04000)
/lib64/ld-linux-x86-64.so.2 (0x00005595dec5f000)
11K executable, linking in standard C stuff.
With my PRs combined with Walter's, we actually have something
useful here.
Note that I used -release on the top program because otherwise
there's linker errors for array bounds checks. I am 100% happy
with this behavior.
More information about the Digitalmars-d
mailing list