From 5f0bfcac24036e1fff0b2beda643a60dad465213 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 6 Jan 2016 06:40:25 -0700 Subject: [PATCH] fix undefined reference to memcpy in release mode when not depending on libc, we generate memcpy and memset implementations. --- CMakeLists.txt | 2 ++ src/codegen.cpp | 38 +++++++++++++++++++++++--------------- std/bootstrap.zig | 2 +- std/builtin.zig | 26 ++++++++++++++++++++++++++ std/std.zig | 31 +------------------------------ std/syscall.zig | 31 +++++++++++++++++++++++++++++++ test/run_tests.cpp | 1 + 7 files changed, 85 insertions(+), 46 deletions(-) create mode 100644 std/builtin.zig create mode 100644 std/syscall.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index e4bbed2433..143fe66206 100644 --- a/CMakeLists.txt +++ b/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" ) diff --git a/src/codegen.cpp b/src/codegen.cpp index f87ca7ef24..3e555a5778 100644 --- a/src/codegen.cpp +++ b/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; } diff --git a/std/bootstrap.zig b/std/bootstrap.zig index 374aa1b9dd..b7b52353f8 100644 --- a/std/bootstrap.zig +++ b/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. diff --git a/std/builtin.zig b/std/builtin.zig new file mode 100644 index 0000000000..0e78eb01bb --- /dev/null +++ b/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; +} diff --git a/std/std.zig b/std/std.zig index ad6acea51d..a53dbb6027 100644 --- a/std/std.zig +++ b/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; diff --git a/std/syscall.zig b/std/syscall.zig new file mode 100644 index 0000000000..1bcbcdbe31 --- /dev/null +++ b/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 +} + diff --git a/test/run_tests.cpp b/test/run_tests.cpp index b44dc6ac7a..661100f6b4 100644 --- a/test/run_tests.cpp +++ b/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; }