authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-18 16:47:30-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-18 16:47:30-05:00
log28bf768883d2411d4cd75582d396d465ab6a54b2
tree542fb1bed1e22462938a62b5caf647c366dfc0c2
parent74a335c4ccd9eb4cfcc5cc6c01b633584c6bb6ba

export _mh_execute_header with weak linkage

* also fix extern variables with initialiaztion values to generate runtime code * remove the workaround in example/shared_library/mathtest.zig * introduce the ability for global variables to have Weak and LinkOnce linkage * fix `@export` to work for non-functions. this code needs to be audited though. * fix comptime ptrcast not keeping bigger alignment * fix linker warnings when targeting darwin closes #1903

10 files changed, 106 insertions(+), 30 deletions(-)

example/shared_library/mathtest.zig-9
...@@ -1,12 +1,3 @@...@@ -1,12 +1,3 @@
1// TODO Remove this workaround
2comptime {
3 const builtin = @import("builtin");
4 if (builtin.os == builtin.Os.macosx) {
5 @export("__mh_execute_header", _mh_execute_header, builtin.GlobalLinkage.Weak);
6 }
7}
8var _mh_execute_header = extern struct {x: usize}{.x = 0};
9
10export fn add(a: i32, b: i32) i32 {1export fn add(a: i32, b: i32) i32 {
11 return a + b;2 return a + b;
12}3}
src/all_types.hpp+3-1
...@@ -1853,7 +1853,9 @@ struct CodeGen {...@@ -1853,7 +1853,9 @@ struct CodeGen {
18531853
1854enum VarLinkage {1854enum VarLinkage {
1855 VarLinkageInternal,1855 VarLinkageInternal,
1856 VarLinkageExport,1856 VarLinkageExportStrong,
1857 VarLinkageExportWeak,
1858 VarLinkageExportLinkOnce,
1857 VarLinkageExternal,1859 VarLinkageExternal,
1858};1860};
18591861
src/analyze.cpp+1-1
...@@ -3746,7 +3746,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {...@@ -3746,7 +3746,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
37463746
3747 VarLinkage linkage;3747 VarLinkage linkage;
3748 if (is_export) {3748 if (is_export) {
3749 linkage = VarLinkageExport;3749 linkage = VarLinkageExportStrong;
3750 } else if (is_extern) {3750 } else if (is_extern) {
3751 linkage = VarLinkageExternal;3751 linkage = VarLinkageExternal;
3752 } else {3752 } else {
src/codegen.cpp+19-3
...@@ -6421,6 +6421,22 @@ static void set_global_tls(CodeGen *g, ZigVar *var, LLVMValueRef global_value) {...@@ -6421,6 +6421,22 @@ static void set_global_tls(CodeGen *g, ZigVar *var, LLVMValueRef global_value) {
6421 }6421 }
6422}6422}
64236423
6424static LLVMLinkage var_linkage_to_llvm(VarLinkage var_linkage) {
6425 switch (var_linkage) {
6426 case VarLinkageInternal:
6427 return LLVMInternalLinkage;
6428 case VarLinkageExportStrong:
6429 return LLVMExternalLinkage;
6430 case VarLinkageExportWeak:
6431 return LLVMWeakODRLinkage;
6432 case VarLinkageExportLinkOnce:
6433 return LLVMLinkOnceODRLinkage;
6434 case VarLinkageExternal:
6435 return LLVMExternalLinkage;
6436 }
6437 zig_unreachable();
6438}
6439
6424static void do_code_gen(CodeGen *g) {6440static void do_code_gen(CodeGen *g) {
6425 assert(!g->errors.length);6441 assert(!g->errors.length);
64266442
...@@ -6501,21 +6517,21 @@ static void do_code_gen(CodeGen *g) {...@@ -6501,21 +6517,21 @@ static void do_code_gen(CodeGen *g) {
6501 global_value = LLVMAddGlobal(g->module, var->var_type->type_ref, buf_ptr(&var->name));6517 global_value = LLVMAddGlobal(g->module, var->var_type->type_ref, buf_ptr(&var->name));
6502 // TODO debug info for the extern variable6518 // TODO debug info for the extern variable
65036519
6504 LLVMSetLinkage(global_value, LLVMExternalLinkage);6520 LLVMSetLinkage(global_value, var_linkage_to_llvm(var->linkage));
6505 maybe_import_dll(g, global_value, GlobalLinkageIdStrong);6521 maybe_import_dll(g, global_value, GlobalLinkageIdStrong);
6506 LLVMSetAlignment(global_value, var->align_bytes);6522 LLVMSetAlignment(global_value, var->align_bytes);
6507 LLVMSetGlobalConstant(global_value, var->gen_is_const);6523 LLVMSetGlobalConstant(global_value, var->gen_is_const);
6508 set_global_tls(g, var, global_value);6524 set_global_tls(g, var, global_value);
6509 }6525 }
6510 } else {6526 } else {
6511 bool exported = (var->linkage == VarLinkageExport);6527 bool exported = (var->linkage != VarLinkageInternal);
6512 const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported));6528 const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported));
6513 render_const_val(g, var->const_value, mangled_name);6529 render_const_val(g, var->const_value, mangled_name);
6514 render_const_val_global(g, var->const_value, mangled_name);6530 render_const_val_global(g, var->const_value, mangled_name);
6515 global_value = var->const_value->global_refs->llvm_global;6531 global_value = var->const_value->global_refs->llvm_global;
65166532
6517 if (exported) {6533 if (exported) {
6518 LLVMSetLinkage(global_value, LLVMExternalLinkage);6534 LLVMSetLinkage(global_value, var_linkage_to_llvm(var->linkage));
6519 maybe_export_dll(g, global_value, GlobalLinkageIdStrong);6535 maybe_export_dll(g, global_value, GlobalLinkageIdStrong);
6520 }6536 }
6521 if (tld_var->section_name) {6537 if (tld_var->section_name) {
src/ir.cpp+53-11
...@@ -13133,6 +13133,20 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,...@@ -13133,6 +13133,20 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
13133 return ir_build_var_decl_gen(ira, &decl_var_instruction->base, var, casted_init_value);13133 return ir_build_var_decl_gen(ira, &decl_var_instruction->base, var, casted_init_value);
13134}13134}
1313513135
13136static VarLinkage global_linkage_to_var_linkage(GlobalLinkageId id) {
13137 switch (id) {
13138 case GlobalLinkageIdStrong:
13139 return VarLinkageExportStrong;
13140 case GlobalLinkageIdWeak:
13141 return VarLinkageExportWeak;
13142 case GlobalLinkageIdLinkOnce:
13143 return VarLinkageExportLinkOnce;
13144 case GlobalLinkageIdInternal:
13145 return VarLinkageInternal;
13146 }
13147 zig_unreachable();
13148}
13149
13136static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) {13150static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) {
13137 IrInstruction *name = instruction->name->child;13151 IrInstruction *name = instruction->name->child;
13138 Buf *symbol_name = ir_resolve_str(ira, name);13152 Buf *symbol_name = ir_resolve_str(ira, name);
...@@ -13161,6 +13175,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio...@@ -13161,6 +13175,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
13161 add_error_note(ira->codegen, msg, other_export_node, buf_sprintf("other symbol is here"));13175 add_error_note(ira->codegen, msg, other_export_node, buf_sprintf("other symbol is here"));
13162 }13176 }
1316313177
13178 bool want_var_export = false;
13164 switch (target->value.type->id) {13179 switch (target->value.type->id) {
13165 case ZigTypeIdInvalid:13180 case ZigTypeIdInvalid:
13166 case ZigTypeIdUnreachable:13181 case ZigTypeIdUnreachable:
...@@ -13196,6 +13211,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio...@@ -13196,6 +13211,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
13196 ErrorMsg *msg = ir_add_error(ira, target,13211 ErrorMsg *msg = ir_add_error(ira, target,
13197 buf_sprintf("exported struct value must be declared extern"));13212 buf_sprintf("exported struct value must be declared extern"));
13198 add_error_note(ira->codegen, msg, target->value.type->data.structure.decl_node, buf_sprintf("declared here"));13213 add_error_note(ira->codegen, msg, target->value.type->data.structure.decl_node, buf_sprintf("declared here"));
13214 } else {
13215 want_var_export = true;
13199 }13216 }
13200 break;13217 break;
13201 case ZigTypeIdUnion:13218 case ZigTypeIdUnion:
...@@ -13203,6 +13220,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio...@@ -13203,6 +13220,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
13203 ErrorMsg *msg = ir_add_error(ira, target,13220 ErrorMsg *msg = ir_add_error(ira, target,
13204 buf_sprintf("exported union value must be declared extern"));13221 buf_sprintf("exported union value must be declared extern"));
13205 add_error_note(ira->codegen, msg, target->value.type->data.unionation.decl_node, buf_sprintf("declared here"));13222 add_error_note(ira->codegen, msg, target->value.type->data.unionation.decl_node, buf_sprintf("declared here"));
13223 } else {
13224 want_var_export = true;
13206 }13225 }
13207 break;13226 break;
13208 case ZigTypeIdEnum:13227 case ZigTypeIdEnum:
...@@ -13210,6 +13229,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio...@@ -13210,6 +13229,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
13210 ErrorMsg *msg = ir_add_error(ira, target,13229 ErrorMsg *msg = ir_add_error(ira, target,
13211 buf_sprintf("exported enum value must be declared extern"));13230 buf_sprintf("exported enum value must be declared extern"));
13212 add_error_note(ira->codegen, msg, target->value.type->data.enumeration.decl_node, buf_sprintf("declared here"));13231 add_error_note(ira->codegen, msg, target->value.type->data.enumeration.decl_node, buf_sprintf("declared here"));
13232 } else {
13233 want_var_export = true;
13213 }13234 }
13214 break;13235 break;
13215 case ZigTypeIdMetaType: {13236 case ZigTypeIdMetaType: {
...@@ -13299,6 +13320,16 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio...@@ -13299,6 +13320,16 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
13299 break;13320 break;
13300 }13321 }
1330113322
13323 // TODO audit the various ways to use @export
13324 if (want_var_export && target->id == IrInstructionIdLoadPtr) {
13325 IrInstructionLoadPtr *load_ptr = reinterpret_cast<IrInstructionLoadPtr *>(target);
13326 if (load_ptr->ptr->id == IrInstructionIdVarPtr) {
13327 IrInstructionVarPtr *var_ptr = reinterpret_cast<IrInstructionVarPtr *>(load_ptr->ptr);
13328 ZigVar *var = var_ptr->var;
13329 var->linkage = global_linkage_to_var_linkage(global_linkage_id);
13330 }
13331 }
13332
13302 return ir_const_void(ira, &instruction->base);13333 return ir_const_void(ira, &instruction->base);
13303}13334}
1330413335
...@@ -13586,9 +13617,16 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,...@@ -13586,9 +13617,16 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
13586 if (var->var_type == nullptr || type_is_invalid(var->var_type))13617 if (var->var_type == nullptr || type_is_invalid(var->var_type))
13587 return ira->codegen->invalid_instruction;13618 return ira->codegen->invalid_instruction;
1358813619
13620 ConstExprValue *mem_slot = nullptr;
13621
13589 bool comptime_var_mem = ir_get_var_is_comptime(var);13622 bool comptime_var_mem = ir_get_var_is_comptime(var);
13623 bool linkage_makes_it_runtime = var->linkage == VarLinkageExternal;
13624 bool is_const = var->src_is_const;
13625 bool is_volatile = false;
13626
13627 if (linkage_makes_it_runtime)
13628 goto no_mem_slot;
1359013629
13591 ConstExprValue *mem_slot = nullptr;
13592 if (var->const_value->special == ConstValSpecialStatic) {13630 if (var->const_value->special == ConstValSpecialStatic) {
13593 mem_slot = var->const_value;13631 mem_slot = var->const_value;
13594 } else {13632 } else {
...@@ -13602,8 +13640,6 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,...@@ -13602,8 +13640,6 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
13602 }13640 }
13603 }13641 }
1360413642
13605 bool is_const = var->src_is_const;
13606 bool is_volatile = false;
13607 if (mem_slot != nullptr) {13643 if (mem_slot != nullptr) {
13608 switch (mem_slot->special) {13644 switch (mem_slot->special) {
13609 case ConstValSpecialRuntime:13645 case ConstValSpecialRuntime:
...@@ -20679,6 +20715,13 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_...@@ -20679,6 +20715,13 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
20679 ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier"));20715 ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier"));
20680 return ira->codegen->invalid_instruction;20716 return ira->codegen->invalid_instruction;
20681 }20717 }
20718 uint32_t src_align_bytes;
20719 if ((err = resolve_ptr_align(ira, src_type, &src_align_bytes)))
20720 return ira->codegen->invalid_instruction;
20721
20722 uint32_t dest_align_bytes;
20723 if ((err = resolve_ptr_align(ira, dest_type, &dest_align_bytes)))
20724 return ira->codegen->invalid_instruction;
2068220725
20683 if (instr_is_comptime(ptr)) {20726 if (instr_is_comptime(ptr)) {
20684 bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type);20727 bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type);
...@@ -20701,16 +20744,15 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_...@@ -20701,16 +20744,15 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
20701 IrInstruction *result = ir_const(ira, source_instr, dest_type);20744 IrInstruction *result = ir_const(ira, source_instr, dest_type);
20702 copy_const_val(&result->value, val, false);20745 copy_const_val(&result->value, val, false);
20703 result->value.type = dest_type;20746 result->value.type = dest_type;
20704 return result;
20705 }
2070620747
20707 uint32_t src_align_bytes;20748 // Keep the bigger alignment, it can only help-
20708 if ((err = resolve_ptr_align(ira, src_type, &src_align_bytes)))20749 // unless the target is zero bits.
20709 return ira->codegen->invalid_instruction;20750 if (src_align_bytes > dest_align_bytes && type_has_bits(dest_type)) {
20751 result = ir_align_cast(ira, result, src_align_bytes, false);
20752 }
2071020753
20711 uint32_t dest_align_bytes;20754 return result;
20712 if ((err = resolve_ptr_align(ira, dest_type, &dest_align_bytes)))20755 }
20713 return ira->codegen->invalid_instruction;
2071420756
20715 if (dest_align_bytes > src_align_bytes) {20757 if (dest_align_bytes > src_align_bytes) {
20716 ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment"));20758 ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment"));
src/link.cpp+8-2
...@@ -899,7 +899,11 @@ static void construct_linker_job_macho(LinkJob *lj) {...@@ -899,7 +899,11 @@ static void construct_linker_job_macho(LinkJob *lj) {
899 lj->args.append("-ios_simulator_version_min");899 lj->args.append("-ios_simulator_version_min");
900 break;900 break;
901 }901 }
902 lj->args.append(buf_ptr(buf_sprintf("%d.%d.%d", platform.major, platform.minor, platform.micro)));902 Buf *version_string = buf_sprintf("%d.%d.%d", platform.major, platform.minor, platform.micro);
903 lj->args.append(buf_ptr(version_string));
904
905 lj->args.append("-sdk_version");
906 lj->args.append(buf_ptr(version_string));
903907
904908
905 if (g->out_type == OutTypeExe) {909 if (g->out_type == OutTypeExe) {
...@@ -920,7 +924,9 @@ static void construct_linker_job_macho(LinkJob *lj) {...@@ -920,7 +924,9 @@ static void construct_linker_job_macho(LinkJob *lj) {
920 add_rpath(lj, &g->output_file_path);924 add_rpath(lj, &g->output_file_path);
921925
922 if (shared) {926 if (shared) {
923 lj->args.append("-headerpad_max_install_names");927 if (g->system_linker_hack) {
928 lj->args.append("-headerpad_max_install_names");
929 }
924 } else if (g->is_static) {930 } else if (g->is_static) {
925 lj->args.append("-lcrt0.o");931 lj->args.append("-lcrt0.o");
926 } else {932 } else {
std/c/darwin.zig+10-1
...@@ -36,11 +36,20 @@ pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usi...@@ -36,11 +36,20 @@ pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usi
36pub extern "c" fn bind(socket: c_int, address: ?*const sockaddr, address_len: socklen_t) c_int;36pub extern "c" fn bind(socket: c_int, address: ?*const sockaddr, address_len: socklen_t) c_int;
37pub extern "c" fn socket(domain: c_int, type: c_int, protocol: c_int) c_int;37pub extern "c" fn socket(domain: c_int, type: c_int, protocol: c_int) c_int;
3838
39const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header;
40
39/// The value of the link editor defined symbol _MH_EXECUTE_SYM is the address41/// The value of the link editor defined symbol _MH_EXECUTE_SYM is the address
40/// of the mach header in a Mach-O executable file type. It does not appear in42/// of the mach header in a Mach-O executable file type. It does not appear in
41/// any file type other than a MH_EXECUTE file type. The type of the symbol is43/// any file type other than a MH_EXECUTE file type. The type of the symbol is
42/// absolute as the header is not part of any section.44/// absolute as the header is not part of any section.
43pub extern "c" var _mh_execute_header: if (@sizeOf(usize) == 8) mach_header_64 else mach_header;45/// This symbol is populated when linking the system's libc, which is guaranteed
46/// on this operating system. However when building object files or libraries,
47/// the system libc won't be linked until the final executable. So we
48/// export a weak symbol here, to be overridden by the real one.
49pub extern "c" var _mh_execute_header: mach_hdr = undefined;
50comptime {
51 @export("__mh_execute_header", _mh_execute_header, @import("builtin").GlobalLinkage.Weak);
52}
4453
45pub const mach_header_64 = macho.mach_header_64;54pub const mach_header_64 = macho.mach_header_64;
46pub const mach_header = macho.mach_header;55pub const mach_header = macho.mach_header;
std/debug/index.zig+1-1
...@@ -574,7 +574,7 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach...@@ -574,7 +574,7 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach
574}574}
575575
576fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {576fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
577 const base_addr = @ptrToInt(&std.c._mh_execute_header);577 const base_addr = std.os.getBaseAddress();
578 const adjusted_addr = 0x100000000 + (address - base_addr);578 const adjusted_addr = 0x100000000 + (address - base_addr);
579579
580 const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {580 const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {
std/os/index.zig+3-1
...@@ -701,7 +701,9 @@ pub fn getBaseAddress() usize {...@@ -701,7 +701,9 @@ pub fn getBaseAddress() usize {
701 const phdr = linuxGetAuxVal(std.elf.AT_PHDR);701 const phdr = linuxGetAuxVal(std.elf.AT_PHDR);
702 return phdr - @sizeOf(std.elf.Ehdr);702 return phdr - @sizeOf(std.elf.Ehdr);
703 },703 },
704 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => return @ptrToInt(&std.c._mh_execute_header),704 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
705 return @ptrToInt(&std.c._mh_execute_header);
706 },
705 builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),707 builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
706 else => @compileError("Unsupported OS"),708 else => @compileError("Unsupported OS"),
707 }709 }
test/stage1/behavior/ptrcast.zig+8
...@@ -50,3 +50,11 @@ const Bytes = struct {...@@ -50,3 +50,11 @@ const Bytes = struct {
50 return res;50 return res;
51 }51 }
52};52};
53
54test "comptime ptrcast keeps larger alignment" {
55 comptime {
56 const a: u32 = 1234;
57 const p = @ptrCast([*]const u8, &a);
58 std.debug.assert(@typeOf(p) == [*]align(@alignOf(u32)) const u8);
59 }
60}