Skip to content

Commit 28bf768

Browse files
committed
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
1 parent 74a335c commit 28bf768

File tree

10 files changed

+106
-30
lines changed

10 files changed

+106
-30
lines changed

example/shared_library/mathtest.zig

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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-
101
export fn add(a: i32, b: i32) i32 {
112
return a + b;
123
}

src/all_types.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1853,7 +1853,9 @@ struct CodeGen {
18531853

18541854
enum VarLinkage {
18551855
VarLinkageInternal,
1856-
VarLinkageExport,
1856+
VarLinkageExportStrong,
1857+
VarLinkageExportWeak,
1858+
VarLinkageExportLinkOnce,
18571859
VarLinkageExternal,
18581860
};
18591861

src/analyze.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3746,7 +3746,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
37463746

37473747
VarLinkage linkage;
37483748
if (is_export) {
3749-
linkage = VarLinkageExport;
3749+
linkage = VarLinkageExportStrong;
37503750
} else if (is_extern) {
37513751
linkage = VarLinkageExternal;
37523752
} else {

src/codegen.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6421,6 +6421,22 @@ static void set_global_tls(CodeGen *g, ZigVar *var, LLVMValueRef global_value) {
64216421
}
64226422
}
64236423

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+
64246440
static void do_code_gen(CodeGen *g) {
64256441
assert(!g->errors.length);
64266442

@@ -6501,21 +6517,21 @@ static void do_code_gen(CodeGen *g) {
65016517
global_value = LLVMAddGlobal(g->module, var->var_type->type_ref, buf_ptr(&var->name));
65026518
// TODO debug info for the extern variable
65036519

6504-
LLVMSetLinkage(global_value, LLVMExternalLinkage);
6520+
LLVMSetLinkage(global_value, var_linkage_to_llvm(var->linkage));
65056521
maybe_import_dll(g, global_value, GlobalLinkageIdStrong);
65066522
LLVMSetAlignment(global_value, var->align_bytes);
65076523
LLVMSetGlobalConstant(global_value, var->gen_is_const);
65086524
set_global_tls(g, var, global_value);
65096525
}
65106526
} else {
6511-
bool exported = (var->linkage == VarLinkageExport);
6527+
bool exported = (var->linkage != VarLinkageInternal);
65126528
const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported));
65136529
render_const_val(g, var->const_value, mangled_name);
65146530
render_const_val_global(g, var->const_value, mangled_name);
65156531
global_value = var->const_value->global_refs->llvm_global;
65166532

65176533
if (exported) {
6518-
LLVMSetLinkage(global_value, LLVMExternalLinkage);
6534+
LLVMSetLinkage(global_value, var_linkage_to_llvm(var->linkage));
65196535
maybe_export_dll(g, global_value, GlobalLinkageIdStrong);
65206536
}
65216537
if (tld_var->section_name) {

src/ir.cpp

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13133,6 +13133,20 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
1313313133
return ir_build_var_decl_gen(ira, &decl_var_instruction->base, var, casted_init_value);
1313413134
}
1313513135

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+
1313613150
static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) {
1313713151
IrInstruction *name = instruction->name->child;
1313813152
Buf *symbol_name = ir_resolve_str(ira, name);
@@ -13161,6 +13175,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
1316113175
add_error_note(ira->codegen, msg, other_export_node, buf_sprintf("other symbol is here"));
1316213176
}
1316313177

13178+
bool want_var_export = false;
1316413179
switch (target->value.type->id) {
1316513180
case ZigTypeIdInvalid:
1316613181
case ZigTypeIdUnreachable:
@@ -13196,20 +13211,26 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
1319613211
ErrorMsg *msg = ir_add_error(ira, target,
1319713212
buf_sprintf("exported struct value must be declared extern"));
1319813213
add_error_note(ira->codegen, msg, target->value.type->data.structure.decl_node, buf_sprintf("declared here"));
13214+
} else {
13215+
want_var_export = true;
1319913216
}
1320013217
break;
1320113218
case ZigTypeIdUnion:
1320213219
if (target->value.type->data.unionation.layout != ContainerLayoutExtern) {
1320313220
ErrorMsg *msg = ir_add_error(ira, target,
1320413221
buf_sprintf("exported union value must be declared extern"));
1320513222
add_error_note(ira->codegen, msg, target->value.type->data.unionation.decl_node, buf_sprintf("declared here"));
13223+
} else {
13224+
want_var_export = true;
1320613225
}
1320713226
break;
1320813227
case ZigTypeIdEnum:
1320913228
if (target->value.type->data.enumeration.layout != ContainerLayoutExtern) {
1321013229
ErrorMsg *msg = ir_add_error(ira, target,
1321113230
buf_sprintf("exported enum value must be declared extern"));
1321213231
add_error_note(ira->codegen, msg, target->value.type->data.enumeration.decl_node, buf_sprintf("declared here"));
13232+
} else {
13233+
want_var_export = true;
1321313234
}
1321413235
break;
1321513236
case ZigTypeIdMetaType: {
@@ -13299,6 +13320,16 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
1329913320
break;
1330013321
}
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+
1330213333
return ir_const_void(ira, &instruction->base);
1330313334
}
1330413335

@@ -13586,9 +13617,16 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
1358613617
if (var->var_type == nullptr || type_is_invalid(var->var_type))
1358713618
return ira->codegen->invalid_instruction;
1358813619

13620+
ConstExprValue *mem_slot = nullptr;
13621+
1358913622
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;
1359213630
if (var->const_value->special == ConstValSpecialStatic) {
1359313631
mem_slot = var->const_value;
1359413632
} else {
@@ -13602,8 +13640,6 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
1360213640
}
1360313641
}
1360413642

13605-
bool is_const = var->src_is_const;
13606-
bool is_volatile = false;
1360713643
if (mem_slot != nullptr) {
1360813644
switch (mem_slot->special) {
1360913645
case ConstValSpecialRuntime:
@@ -20679,6 +20715,13 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
2067920715
ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier"));
2068020716
return ira->codegen->invalid_instruction;
2068120717
}
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

2068320726
if (instr_is_comptime(ptr)) {
2068420727
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_
2070120744
IrInstruction *result = ir_const(ira, source_instr, dest_type);
2070220745
copy_const_val(&result->value, val, false);
2070320746
result->value.type = dest_type;
20704-
return result;
20705-
}
2070620747

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+
}
2071020753

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+
}
2071420756

2071520757
if (dest_align_bytes > src_align_bytes) {
2071620758
ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment"));

src/link.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,11 @@ static void construct_linker_job_macho(LinkJob *lj) {
899899
lj->args.append("-ios_simulator_version_min");
900900
break;
901901
}
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

905909
if (g->out_type == OutTypeExe) {
@@ -920,7 +924,9 @@ static void construct_linker_job_macho(LinkJob *lj) {
920924
add_rpath(lj, &g->output_file_path);
921925

922926
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+
}
924930
} else if (g->is_static) {
925931
lj->args.append("-lcrt0.o");
926932
} else {

std/c/darwin.zig

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,20 @@ pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usi
3636
pub extern "c" fn bind(socket: c_int, address: ?*const sockaddr, address_len: socklen_t) c_int;
3737
pub extern "c" fn socket(domain: c_int, type: c_int, protocol: c_int) c_int;
3838

39+
const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header;
40+
3941
/// The value of the link editor defined symbol _MH_EXECUTE_SYM is the address
4042
/// of the mach header in a Mach-O executable file type. It does not appear in
4143
/// any file type other than a MH_EXECUTE file type. The type of the symbol is
4244
/// 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+
}
4453

4554
pub const mach_header_64 = macho.mach_header_64;
4655
pub const mach_header = macho.mach_header;

std/debug/index.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach
574574
}
575575

576576
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();
578578
const adjusted_addr = 0x100000000 + (address - base_addr);
579579

580580
const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {

std/os/index.zig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,9 @@ pub fn getBaseAddress() usize {
701701
const phdr = linuxGetAuxVal(std.elf.AT_PHDR);
702702
return phdr - @sizeOf(std.elf.Ehdr);
703703
},
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+
},
705707
builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
706708
else => @compileError("Unsupported OS"),
707709
}

test/stage1/behavior/ptrcast.zig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,11 @@ const Bytes = struct {
5050
return res;
5151
}
5252
};
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+
}

0 commit comments

Comments
 (0)