Commit 592210a173

Andrew Kelley <superjoe30@gmail.com>
2016-02-12 10:04:46
i386 support
closes #115 Thanks to Seo Sanghyeon for the port code.
1 parent 0c1ce21
src/link.cpp
@@ -80,14 +80,68 @@ static const char *get_exe_file_extension(CodeGen *g) {
     }
 }
 
+static const char *getLDMOption(const ZigTarget *t) {
+    switch (t->arch.arch) {
+        case ZigLLVM_x86:
+            return "elf_i386";
+        case ZigLLVM_aarch64:
+            return "aarch64linux";
+        case ZigLLVM_aarch64_be:
+            return "aarch64_be_linux";
+        case ZigLLVM_arm:
+        case ZigLLVM_thumb:
+            return "armelf_linux_eabi";
+        case ZigLLVM_armeb:
+        case ZigLLVM_thumbeb:
+            return "armebelf_linux_eabi";
+        case ZigLLVM_ppc:
+            return "elf32ppclinux";
+        case ZigLLVM_ppc64:
+            return "elf64ppc";
+        case ZigLLVM_ppc64le:
+            return "elf64lppc";
+        case ZigLLVM_sparc:
+        case ZigLLVM_sparcel:
+            return "elf32_sparc";
+        case ZigLLVM_sparcv9:
+            return "elf64_sparc";
+        case ZigLLVM_mips:
+            return "elf32btsmip";
+        case ZigLLVM_mipsel:
+            return "elf32ltsmip";
+            return "elf64btsmip";
+        case ZigLLVM_mips64el:
+            return "elf64ltsmip";
+        case ZigLLVM_systemz:
+            return "elf64_s390";
+        case ZigLLVM_x86_64:
+            if (t->environ == ZigLLVM_GNUX32) {
+                return "elf32_x86_64";
+            }
+            return "elf_x86_64";
+        default:
+            zig_unreachable();
+    }
+}
+
 static void construct_linker_job_linux(LinkJob *lj) {
     CodeGen *g = lj->codegen;
 
     lj->args.append("-m");
-    lj->args.append("elf_x86_64");
+    lj->args.append(getLDMOption(&g->zig_target));
 
+    bool is_lib = g->out_type == OutTypeLib;
+    bool shared = !g->is_static && is_lib;
     if (g->is_static) {
-        lj->args.append("-static");
+        if (g->zig_target.arch.arch == ZigLLVM_arm || g->zig_target.arch.arch == ZigLLVM_armeb ||
+            g->zig_target.arch.arch == ZigLLVM_thumb || g->zig_target.arch.arch == ZigLLVM_thumbeb)
+        {
+            lj->args.append("-Bstatic");
+        } else {
+            lj->args.append("-static");
+        }
+    } else if (shared) {
+        lj->args.append("-shared");
     }
 
     lj->args.append("-o");
@@ -135,7 +189,6 @@ static void construct_linker_job_linux(LinkJob *lj) {
         buf_appendf(&lj->out_file, "lib%s.so.%d.%d.%d",
                 buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch);
         Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->root_out_name), g->version_major);
-        lj->args.append("-shared");
         lj->args.append("-soname");
         lj->args.append(buf_ptr(soname));
     }
std/bootstrap.zig
@@ -9,9 +9,19 @@ var env: &&u8 = undefined;
 
 #attribute("naked")
 export fn _start() -> unreachable {
-    argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> isize));
-    argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));
-    env = asm("lea 0x10(%%rsp,%%rdi,8), %[env]": [env] "=r" (-> &&u8));
+    switch (@compile_var("arch")) {
+        x86_64 => {
+            argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> isize));
+            argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));
+            env = asm("lea 0x10(%%rsp,[argc],8), %[env]": [env] "=r" (-> &&u8): [argc] "r" (argc));
+        },
+        i386 => {
+            argc = asm("mov (%%esp), %[argc]": [argc] "=r" (-> isize));
+            argv = asm("lea 0x4(%%esp), %[argv]": [argv] "=r" (-> &&u8));
+            env = asm("lea 0x8(%%esp,%[argc],4), %[env]": [env] "=r" (-> &&u8): [argc] "r" (argc));
+        },
+        else => unreachable{},
+    }
     call_main()
 }
 
std/syscall.zig
@@ -1,17 +1,63 @@
-// this file is specific to x86_64
-
-const SYS_read           = 0;
-const SYS_write          = 1;
-const SYS_mmap           = 9;
-const SYS_munmap         = 11;
-const SYS_rt_sigprocmask = 14;
-const SYS_exit           = 60;
-const SYS_kill           = 62;
-const SYS_getgid         = 104;
-const SYS_gettid         = 186;
-const SYS_tkill          = 200;
-const SYS_tgkill         = 234;
-const SYS_getrandom      = 318;
+const SYS_read = switch (@compile_var("arch")) {
+    x86_64 => 0,
+    i386 => 3,
+    else => unreachable{},
+};
+const SYS_write = switch (@compile_var("arch")) {
+    x86_64 => 1,
+    i386 => 4,
+    else => unreachable{},
+};
+const SYS_mmap = switch (@compile_var("arch")) {
+    x86_64 => 9,
+    i386 => 90,
+    else => unreachable{},
+};
+const SYS_munmap = switch (@compile_var("arch")) {
+    x86_64 => 11,
+    i386 => 91,
+    else => unreachable{},
+};
+const SYS_rt_sigprocmask = switch (@compile_var("arch")) {
+    x86_64 => 14,
+    i386 => 175,
+    else => unreachable{},
+};
+const SYS_exit = switch (@compile_var("arch")) {
+    x86_64 => 60,
+    i386 => 1,
+    else => unreachable{},
+};
+const SYS_kill = switch (@compile_var("arch")) {
+    x86_64 => 62,
+    i386 => 37,
+    else => unreachable{},
+};
+const SYS_getgid = switch (@compile_var("arch")) {
+    x86_64 => 104,
+    i386 => 47,
+    else => unreachable{},
+};
+const SYS_gettid = switch (@compile_var("arch")) {
+    x86_64 => 186,
+    i386 => 224,
+    else => unreachable{},
+};
+const SYS_tkill = switch (@compile_var("arch")) {
+    x86_64 => 200,
+    i386 => 238,
+    else => unreachable{},
+};
+const SYS_tgkill = switch (@compile_var("arch")) {
+    x86_64 => 234,
+    i386 => 270,
+    else => unreachable{},
+};
+const SYS_getrandom = switch (@compile_var("arch")) {
+    x86_64 => 318,
+    i386 => 355,
+    else => unreachable{},
+};
 
 pub const MMAP_PROT_NONE =  0;
 pub const MMAP_PROT_READ =  1;
@@ -63,14 +109,45 @@ const SIG_BLOCK   = 0;
 const SIG_UNBLOCK = 1;
 const SIG_SETMASK = 2;
 
-fn syscall0(number: isize) -> isize {
+const syscall0 = switch (@compile_var("arch")) {
+    x86_64 => x86_64_syscall0,
+    i386 => i386_syscall0,
+    else => unreachable{},
+};
+const syscall1 = switch (@compile_var("arch")) {
+    x86_64 => x86_64_syscall1,
+    i386 => i386_syscall1,
+    else => unreachable{},
+};
+const syscall2 = switch (@compile_var("arch")) {
+    x86_64 => x86_64_syscall2,
+    i386 => i386_syscall2,
+    else => unreachable{},
+};
+const syscall3 = switch (@compile_var("arch")) {
+    x86_64 => x86_64_syscall3,
+    i386 => i386_syscall3,
+    else => unreachable{},
+};
+const syscall4 = switch (@compile_var("arch")) {
+    x86_64 => x86_64_syscall4,
+    i386 => i386_syscall4,
+    else => unreachable{},
+};
+const syscall6 = switch (@compile_var("arch")) {
+    x86_64 => x86_64_syscall6,
+    i386 => i386_syscall6,
+    else => unreachable{},
+};
+
+fn x86_64_syscall0(number: isize) -> isize {
     asm volatile ("syscall"
         : [ret] "={rax}" (-> isize)
         : [number] "{rax}" (number)
         : "rcx", "r11")
 }
 
-fn syscall1(number: isize, arg1: isize) -> isize {
+fn x86_64_syscall1(number: isize, arg1: isize) -> isize {
     asm volatile ("syscall"
         : [ret] "={rax}" (-> isize)
         : [number] "{rax}" (number),
@@ -78,7 +155,7 @@ fn syscall1(number: isize, arg1: isize) -> isize {
         : "rcx", "r11")
 }
 
-fn syscall2(number: isize, arg1: isize, arg2: isize) -> isize {
+fn x86_64_syscall2(number: isize, arg1: isize, arg2: isize) -> isize {
     asm volatile ("syscall"
         : [ret] "={rax}" (-> isize)
         : [number] "{rax}" (number),
@@ -87,7 +164,7 @@ fn syscall2(number: isize, arg1: isize, arg2: isize) -> isize {
         : "rcx", "r11")
 }
 
-fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
+fn x86_64_syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
     asm volatile ("syscall"
         : [ret] "={rax}" (-> isize)
         : [number] "{rax}" (number),
@@ -97,7 +174,7 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
         : "rcx", "r11")
 }
 
-fn syscall4(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize) -> isize {
+fn x86_64_syscall4(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize) -> isize {
     asm volatile ("syscall"
         : [ret] "={rax}" (-> isize)
         : [number] "{rax}" (number),
@@ -108,7 +185,7 @@ fn syscall4(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize) -
         : "rcx", "r11")
 }
 
-fn syscall6(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize, arg5: isize, arg6: isize) -> isize {
+fn x86_64_syscall6(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize, arg5: isize, arg6: isize) -> isize {
     asm volatile ("syscall"
         : [ret] "={rax}" (-> isize)
         : [number] "{rax}" (number),
@@ -121,6 +198,58 @@ fn syscall6(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize, a
         : "rcx", "r11")
 }
 
+fn i386_syscall0(number: isize) -> isize {
+    asm volatile ("int $0x80"
+        : [ret] "={eax}" (-> isize)
+        : [number] "{eax}" (number))
+}
+
+fn i386_syscall1(number: isize, arg1: isize) -> isize {
+    asm volatile ("int $0x80"
+        : [ret] "={eax}" (-> isize)
+        : [number] "{eax}" (number),
+            [arg1] "{ebx}" (arg1))
+}
+
+fn i386_syscall2(number: isize, arg1: isize, arg2: isize) -> isize {
+    asm volatile ("int $0x80"
+        : [ret] "={eax}" (-> isize)
+        : [number] "{eax}" (number),
+            [arg1] "{ebx}" (arg1),
+            [arg2] "{ecx}" (arg2))
+}
+
+fn i386_syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
+    asm volatile ("int $0x80"
+        : [ret] "={eax}" (-> isize)
+        : [number] "{eax}" (number),
+            [arg1] "{ebx}" (arg1),
+            [arg2] "{ecx}" (arg2),
+            [arg3] "{edx}" (arg3))
+}
+
+fn i386_syscall4(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize) -> isize {
+    asm volatile ("int $0x80"
+        : [ret] "={eax}" (-> isize)
+        : [number] "{eax}" (number),
+            [arg1] "{ebx}" (arg1),
+            [arg2] "{ecx}" (arg2),
+            [arg3] "{edx}" (arg3),
+            [arg4] "{esi}" (arg4))
+}
+
+fn i386_syscall6(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize, arg5: isize, arg6: isize) -> isize {
+    asm volatile ("int $0x80"
+        : [ret] "={eax}" (-> isize)
+        : [number] "{eax}" (number),
+            [arg1] "{ebx}" (arg1),
+            [arg2] "{ecx}" (arg2),
+            [arg3] "{edx}" (arg3),
+            [arg4] "{esi}" (arg4),
+            [arg5] "{edi}" (arg5),
+            [arg6] "{ebp}" (arg6))
+}
+
 pub fn mmap(address: isize, length: isize, prot: isize, flags: isize, fd: isize, offset: isize) -> isize {
     syscall6(SYS_mmap, address, length, prot, flags, fd, offset)
 }
test/self_hosted.zig
@@ -164,7 +164,12 @@ fn enum_type() {
     assert(bar == EnumTypeBar.B);
     assert(@member_count(EnumTypeFoo) == 3);
     assert(@member_count(EnumTypeBar) == 4);
-    assert(@sizeof(EnumTypeFoo) == 24);
+    const expected_foo_size = switch (@compile_var("arch")) {
+        i386 => 20,
+        x86_64 => 24,
+        else => unreachable{},
+    };
+    assert(@sizeof(EnumTypeFoo) == expected_foo_size);
     assert(@sizeof(EnumTypeBar) == 1);
 }
 struct EnumType {