From 592210a1739dfe3fe506260c11b8b5e5d8a5a715 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 12 Feb 2016 02:04:46 -0700 Subject: [PATCH] i386 support closes #115 Thanks to Seo Sanghyeon for the port code. --- src/link.cpp | 59 ++++++++++++++- std/bootstrap.zig | 16 +++- std/syscall.zig | 169 ++++++++++++++++++++++++++++++++++++++----- test/self_hosted.zig | 7 +- 4 files changed, 224 insertions(+), 27 deletions(-) diff --git a/src/link.cpp b/src/link.cpp index 753e30d05..318d6ffa3 100644 --- a/src/link.cpp +++ b/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)); } diff --git a/std/bootstrap.zig b/std/bootstrap.zig index 75edc2948..091d7c77c 100644 --- a/std/bootstrap.zig +++ b/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() } diff --git a/std/syscall.zig b/std/syscall.zig index a99839ded..669fb2b8c 100644 --- a/std/syscall.zig +++ b/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) } diff --git a/test/self_hosted.zig b/test/self_hosted.zig index 87fb71fb2..a35b2a5ff 100644 --- a/test/self_hosted.zig +++ b/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 {