Commit 5f0bfcac24

Andrew Kelley <superjoe30@gmail.com>
2016-01-06 14:40:25
fix undefined reference to memcpy in release mode
when not depending on libc, we generate memcpy and memset implementations.
1 parent 5e64c4d
src/codegen.cpp
@@ -2179,6 +2179,24 @@ done_looking_at_imports:
     return import_entry;
 }
 
+static ImportTableEntry *add_special_code(CodeGen *g, const char *basename) {
+    Buf *std_dir = buf_create_from_str(ZIG_STD_DIR);
+    Buf *code_basename = buf_create_from_str(basename);
+    Buf path_to_code_src = BUF_INIT;
+    os_path_join(std_dir, code_basename, &path_to_code_src);
+    Buf *abs_full_path = buf_alloc();
+    int err;
+    if ((err = os_path_real(&path_to_code_src, abs_full_path))) {
+        zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
+    }
+    Buf *import_code = buf_alloc();
+    if ((err = os_fetch_file_path(abs_full_path, import_code))) {
+        zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
+    }
+
+    return codegen_add_code(g, abs_full_path, std_dir, code_basename, import_code);
+}
+
 void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *source_code) {
     Buf source_path = BUF_INIT;
     os_path_join(src_dir, src_basename, &source_path);
@@ -2192,22 +2210,12 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou
 
     g->root_import = codegen_add_code(g, abs_full_path, src_dir, src_basename, source_code);
 
-    if (g->have_exported_main && !g->link_libc && g->out_type != OutTypeLib) {
-        Buf *bootstrap_dir = buf_create_from_str(ZIG_STD_DIR);
-        Buf *bootstrap_basename = buf_create_from_str("bootstrap.zig");
-        Buf path_to_bootstrap_src = BUF_INIT;
-        os_path_join(bootstrap_dir, bootstrap_basename, &path_to_bootstrap_src);
-        Buf *abs_full_path = buf_alloc();
-        if ((err = os_path_real(&path_to_bootstrap_src, abs_full_path))) {
-            zig_panic("unable to open '%s': %s", buf_ptr(&path_to_bootstrap_src), err_str(err));
-        }
-        Buf *import_code = buf_alloc();
-        int err;
-        if ((err = os_fetch_file_path(abs_full_path, import_code))) {
-            zig_panic("unable to open '%s': %s", buf_ptr(&path_to_bootstrap_src), err_str(err));
+    if (!g->link_libc) {
+        if (g->have_exported_main && g->out_type != OutTypeLib) {
+            g->bootstrap_import = add_special_code(g, "bootstrap.zig");
         }
 
-        g->bootstrap_import = codegen_add_code(g, abs_full_path, bootstrap_dir, bootstrap_basename, import_code);
+        add_special_code(g, "builtin.zig");
     }
 
     if (g->verbose) {
@@ -2417,7 +2425,7 @@ void codegen_link(CodeGen *g, const char *out_file) {
         // invoke `ar`
         // example:
         // # static link into libfoo.a
-        // ar cq libfoo.a foo1.o foo2.o 
+        // ar rcs libfoo.a foo1.o foo2.o 
         zig_panic("TODO invoke ar");
         return;
     }
std/bootstrap.zig
@@ -1,4 +1,4 @@
-use "std.zig";
+use "syscall.zig";
 
 // The compiler treats this file special by implicitly importing the function `main`
 // from the root source file.
std/builtin.zig
@@ -0,0 +1,26 @@
+// These functions are provided when not linking against libc because LLVM
+// sometimes generates code that calls them.
+
+// In the future we may put these functions in separate compile units, make them .o files,
+// and then use
+// ar rcs foo.a foo.o memcpy.o memset.o
+// ld -o foo foo.a
+// This will omit the machine code if the function is unused.
+
+export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {
+    var index : #typeof(n) = 0;
+    while (index != n) {
+        dest[index] = c;
+        index += 1;
+    }
+    return dest;
+}
+
+export fn memcpy(dest: &u8, src: &const u8, n: usize) -> &u8 {
+    var index : #typeof(n) = 0;
+    while (index != n) {
+        dest[index] = src[index];
+        index += 1;
+    }
+    return dest;
+}
std/std.zig
@@ -1,33 +1,4 @@
-const SYS_write : usize = 1;
-const SYS_exit : usize = 60;
-const SYS_getrandom : usize = 318;
-
-fn syscall1(number: usize, arg1: usize) -> usize {
-    asm volatile ("syscall"
-        : [ret] "={rax}" (-> usize)
-        : [number] "{rax}" (number), [arg1] "{rdi}" (arg1)
-        : "rcx", "r11")
-}
-
-fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
-    asm volatile ("syscall"
-        : [ret] "={rax}" (-> usize)
-        : [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2), [arg3] "{rdx}" (arg3)
-        : "rcx", "r11")
-}
-
-pub fn write(fd: isize, buf: &const u8, count: usize) -> isize {
-    syscall3(SYS_write, fd as usize, buf as usize, count) as isize
-}
-
-pub fn exit(status: i32) -> unreachable {
-    syscall1(SYS_exit, status as usize);
-    unreachable
-}
-
-pub fn getrandom(buf: &u8, count: usize, flags: u32) -> isize {
-    syscall3(SYS_getrandom, buf as usize, count, flags as usize) as isize
-}
+use "syscall.zig";
 
 const stdout_fileno : isize = 1;
 const stderr_fileno : isize = 2;
std/syscall.zig
@@ -0,0 +1,31 @@
+const SYS_write : usize = 1;
+const SYS_exit : usize = 60;
+const SYS_getrandom : usize = 318;
+
+fn syscall1(number: usize, arg1: usize) -> usize {
+    asm volatile ("syscall"
+        : [ret] "={rax}" (-> usize)
+        : [number] "{rax}" (number), [arg1] "{rdi}" (arg1)
+        : "rcx", "r11")
+}
+
+fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
+    asm volatile ("syscall"
+        : [ret] "={rax}" (-> usize)
+        : [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2), [arg3] "{rdx}" (arg3)
+        : "rcx", "r11")
+}
+
+pub fn write(fd: isize, buf: &const u8, count: usize) -> isize {
+    syscall3(SYS_write, fd as usize, buf as usize, count) as isize
+}
+
+pub fn exit(status: i32) -> unreachable {
+    syscall1(SYS_exit, status as usize);
+    unreachable
+}
+
+pub fn getrandom(buf: &u8, count: usize, flags: u32) -> isize {
+    syscall3(SYS_getrandom, buf as usize, count, flags as usize) as isize
+}
+
test/run_tests.cpp
@@ -109,6 +109,7 @@ static void add_compiling_test_cases(void) {
 
     add_simple_case("function call", R"SOURCE(
         use "std.zig";
+        use "syscall.zig";
 
         fn empty_function_1() {}
         fn empty_function_2() { return; }
CMakeLists.txt
@@ -117,7 +117,9 @@ set(C_HEADERS
 
 set(ZIG_STD_SRC
     "${CMAKE_SOURCE_DIR}/std/bootstrap.zig"
+    "${CMAKE_SOURCE_DIR}/std/builtin.zig"
     "${CMAKE_SOURCE_DIR}/std/std.zig"
+    "${CMAKE_SOURCE_DIR}/std/syscall.zig"
     "${CMAKE_SOURCE_DIR}/std/rand.zig"
 )