| author | |
| committer | |
| log | 28bf768883d2411d4cd75582d396d465ab6a54b2 |
| tree | 542fb1bed1e22462938a62b5caf647c366dfc0c2 |
| parent | 74a335c4ccd9eb4cfcc5cc6c01b633584c6bb6ba |
* 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 #190310 files changed, 106 insertions(+), 30 deletions(-)
example/shared_library/mathtest.zig-9| ... | ... | @@ -1,12 +1,3 @@ |
| 1 | // TODO Remove this workaround | |
| 2 | comptime { | |
| 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 | } | |
| 8 | var _mh_execute_header = extern struct {x: usize}{.x = 0}; | |
| 9 | ||
| 10 | 1 | export fn add(a: i32, b: i32) i32 { |
| 11 | 2 | return a + b; |
| 12 | 3 | } |
src/all_types.hpp+3-1| ... | ... | @@ -1853,7 +1853,9 @@ struct CodeGen { |
| 1853 | 1853 | |
| 1854 | 1854 | enum VarLinkage { |
| 1855 | 1855 | VarLinkageInternal, |
| 1856 | VarLinkageExport, | |
| 1856 | VarLinkageExportStrong, | |
| 1857 | VarLinkageExportWeak, | |
| 1858 | VarLinkageExportLinkOnce, | |
| 1857 | 1859 | VarLinkageExternal, |
| 1858 | 1860 | }; |
| 1859 | 1861 |
src/analyze.cpp+1-1| ... | ... | @@ -3746,7 +3746,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { |
| 3746 | 3746 | |
| 3747 | 3747 | VarLinkage linkage; |
| 3748 | 3748 | if (is_export) { |
| 3749 | linkage = VarLinkageExport; | |
| 3749 | linkage = VarLinkageExportStrong; | |
| 3750 | 3750 | } else if (is_extern) { |
| 3751 | 3751 | linkage = VarLinkageExternal; |
| 3752 | 3752 | } else { |
src/codegen.cpp+19-3| ... | ... | @@ -6421,6 +6421,22 @@ static void set_global_tls(CodeGen *g, ZigVar *var, LLVMValueRef global_value) { |
| 6421 | 6421 | } |
| 6422 | 6422 | } |
| 6423 | 6423 | |
| 6424 | static 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 | ||
| 6424 | 6440 | static void do_code_gen(CodeGen *g) { |
| 6425 | 6441 | assert(!g->errors.length); |
| 6426 | 6442 | |
| ... | ... | @@ -6501,21 +6517,21 @@ static void do_code_gen(CodeGen *g) { |
| 6501 | 6517 | global_value = LLVMAddGlobal(g->module, var->var_type->type_ref, buf_ptr(&var->name)); |
| 6502 | 6518 | // TODO debug info for the extern variable |
| 6503 | 6519 | |
| 6504 | LLVMSetLinkage(global_value, LLVMExternalLinkage); | |
| 6520 | LLVMSetLinkage(global_value, var_linkage_to_llvm(var->linkage)); | |
| 6505 | 6521 | maybe_import_dll(g, global_value, GlobalLinkageIdStrong); |
| 6506 | 6522 | LLVMSetAlignment(global_value, var->align_bytes); |
| 6507 | 6523 | LLVMSetGlobalConstant(global_value, var->gen_is_const); |
| 6508 | 6524 | set_global_tls(g, var, global_value); |
| 6509 | 6525 | } |
| 6510 | 6526 | } else { |
| 6511 | bool exported = (var->linkage == VarLinkageExport); | |
| 6527 | bool exported = (var->linkage != VarLinkageInternal); | |
| 6512 | 6528 | const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported)); |
| 6513 | 6529 | render_const_val(g, var->const_value, mangled_name); |
| 6514 | 6530 | render_const_val_global(g, var->const_value, mangled_name); |
| 6515 | 6531 | global_value = var->const_value->global_refs->llvm_global; |
| 6516 | 6532 | |
| 6517 | 6533 | if (exported) { |
| 6518 | LLVMSetLinkage(global_value, LLVMExternalLinkage); | |
| 6534 | LLVMSetLinkage(global_value, var_linkage_to_llvm(var->linkage)); | |
| 6519 | 6535 | maybe_export_dll(g, global_value, GlobalLinkageIdStrong); |
| 6520 | 6536 | } |
| 6521 | 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 | 13133 | return ir_build_var_decl_gen(ira, &decl_var_instruction->base, var, casted_init_value); |
| 13134 | 13134 | } |
| 13135 | 13135 | |
| 13136 | static 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 | ||
| 13136 | 13150 | static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) { |
| 13137 | 13151 | IrInstruction *name = instruction->name->child; |
| 13138 | 13152 | Buf *symbol_name = ir_resolve_str(ira, name); |
| ... | ... | @@ -13161,6 +13175,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio |
| 13161 | 13175 | add_error_note(ira->codegen, msg, other_export_node, buf_sprintf("other symbol is here")); |
| 13162 | 13176 | } |
| 13163 | 13177 | |
| 13178 | bool want_var_export = false; | |
| 13164 | 13179 | switch (target->value.type->id) { |
| 13165 | 13180 | case ZigTypeIdInvalid: |
| 13166 | 13181 | case ZigTypeIdUnreachable: |
| ... | ... | @@ -13196,6 +13211,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio |
| 13196 | 13211 | ErrorMsg *msg = ir_add_error(ira, target, |
| 13197 | 13212 | buf_sprintf("exported struct value must be declared extern")); |
| 13198 | 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 | 13217 | break; |
| 13201 | 13218 | case ZigTypeIdUnion: |
| ... | ... | @@ -13203,6 +13220,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio |
| 13203 | 13220 | ErrorMsg *msg = ir_add_error(ira, target, |
| 13204 | 13221 | buf_sprintf("exported union value must be declared extern")); |
| 13205 | 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 | 13226 | break; |
| 13208 | 13227 | case ZigTypeIdEnum: |
| ... | ... | @@ -13210,6 +13229,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio |
| 13210 | 13229 | ErrorMsg *msg = ir_add_error(ira, target, |
| 13211 | 13230 | buf_sprintf("exported enum value must be declared extern")); |
| 13212 | 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 | 13235 | break; |
| 13215 | 13236 | case ZigTypeIdMetaType: { |
| ... | ... | @@ -13299,6 +13320,16 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio |
| 13299 | 13320 | break; |
| 13300 | 13321 | } |
| 13301 | 13322 | |
| 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 | 13333 | return ir_const_void(ira, &instruction->base); |
| 13303 | 13334 | } |
| 13304 | 13335 | |
| ... | ... | @@ -13586,9 +13617,16 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 13586 | 13617 | if (var->var_type == nullptr || type_is_invalid(var->var_type)) |
| 13587 | 13618 | return ira->codegen->invalid_instruction; |
| 13588 | 13619 | |
| 13620 | ConstExprValue *mem_slot = nullptr; | |
| 13621 | ||
| 13589 | 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; | |
| 13590 | 13629 | |
| 13591 | ConstExprValue *mem_slot = nullptr; | |
| 13592 | 13630 | if (var->const_value->special == ConstValSpecialStatic) { |
| 13593 | 13631 | mem_slot = var->const_value; |
| 13594 | 13632 | } else { |
| ... | ... | @@ -13602,8 +13640,6 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 13602 | 13640 | } |
| 13603 | 13641 | } |
| 13604 | 13642 | |
| 13605 | bool is_const = var->src_is_const; | |
| 13606 | bool is_volatile = false; | |
| 13607 | 13643 | if (mem_slot != nullptr) { |
| 13608 | 13644 | switch (mem_slot->special) { |
| 13609 | 13645 | case ConstValSpecialRuntime: |
| ... | ... | @@ -20679,6 +20715,13 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ |
| 20679 | 20715 | ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier")); |
| 20680 | 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; | |
| 20682 | 20725 | |
| 20683 | 20726 | if (instr_is_comptime(ptr)) { |
| 20684 | 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 | 20744 | IrInstruction *result = ir_const(ira, source_instr, dest_type); |
| 20702 | 20745 | copy_const_val(&result->value, val, false); |
| 20703 | 20746 | result->value.type = dest_type; |
| 20704 | return result; | |
| 20705 | } | |
| 20706 | 20747 | |
| 20707 | uint32_t src_align_bytes; | |
| 20708 | if ((err = resolve_ptr_align(ira, src_type, &src_align_bytes))) | |
| 20709 | return ira->codegen->invalid_instruction; | |
| 20748 | // Keep the bigger alignment, it can only help- | |
| 20749 | // unless the target is zero bits. | |
| 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 | } | |
| 20710 | 20753 | |
| 20711 | uint32_t dest_align_bytes; | |
| 20712 | if ((err = resolve_ptr_align(ira, dest_type, &dest_align_bytes))) | |
| 20713 | return ira->codegen->invalid_instruction; | |
| 20754 | return result; | |
| 20755 | } | |
| 20714 | 20756 | |
| 20715 | 20757 | if (dest_align_bytes > src_align_bytes) { |
| 20716 | 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 | 899 | lj->args.append("-ios_simulator_version_min"); |
| 900 | 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)); | |
| 903 | 907 | |
| 904 | 908 | |
| 905 | 909 | if (g->out_type == OutTypeExe) { |
| ... | ... | @@ -920,7 +924,9 @@ static void construct_linker_job_macho(LinkJob *lj) { |
| 920 | 924 | add_rpath(lj, &g->output_file_path); |
| 921 | 925 | |
| 922 | 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 | 930 | } else if (g->is_static) { |
| 925 | 931 | lj->args.append("-lcrt0.o"); |
| 926 | 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 | 36 | pub extern "c" fn bind(socket: c_int, address: ?*const sockaddr, address_len: socklen_t) c_int; |
| 37 | 37 | pub extern "c" fn socket(domain: c_int, type: c_int, protocol: c_int) c_int; |
| 38 | 38 | |
| 39 | const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header; | |
| 40 | ||
| 39 | 41 | /// The value of the link editor defined symbol _MH_EXECUTE_SYM is the address |
| 40 | 42 | /// of the mach header in a Mach-O executable file type. It does not appear in |
| 41 | 43 | /// any file type other than a MH_EXECUTE file type. The type of the symbol is |
| 42 | 44 | /// absolute as the header is not part of any section. |
| 43 | pub 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. | |
| 49 | pub extern "c" var _mh_execute_header: mach_hdr = undefined; | |
| 50 | comptime { | |
| 51 | @export("__mh_execute_header", _mh_execute_header, @import("builtin").GlobalLinkage.Weak); | |
| 52 | } | |
| 44 | 53 | |
| 45 | 54 | pub const mach_header_64 = macho.mach_header_64; |
| 46 | 55 | pub 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 | 574 | } |
| 575 | 575 | |
| 576 | 576 | fn 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 | 578 | const adjusted_addr = 0x100000000 + (address - base_addr); |
| 579 | 579 | |
| 580 | 580 | const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse { |
std/os/index.zig+3-1| ... | ... | @@ -701,7 +701,9 @@ pub fn getBaseAddress() usize { |
| 701 | 701 | const phdr = linuxGetAuxVal(std.elf.AT_PHDR); |
| 702 | 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 | 707 | builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)), |
| 706 | 708 | else => @compileError("Unsupported OS"), |
| 707 | 709 | } |
test/stage1/behavior/ptrcast.zig+8| ... | ... | @@ -50,3 +50,11 @@ const Bytes = struct { |
| 50 | 50 | return res; |
| 51 | 51 | } |
| 52 | 52 | }; |
| 53 | ||
| 54 | test "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 | } |