| author | |
| committer | |
| log | 274fd8a5697ed40fb8cd3956707dbf4db3964e22 |
| tree | 4f88663a9a7493d9b730075820efb6ef496bad1c |
| parent | 4e293f3e4d6c7072962513bee0ca8643becb81aa |
Partially resolves https://codeberg.org/ziglang/zig/issues/36986, but
does not folly resolve it---the bug still exists in the C backend and
the self-hosted WASM and Mach-O linkers.5 files changed, 46 insertions(+), 31 deletions(-)
lib/std/zig/llvm/Builder.zig+1-1| ... | ... | @@ -3483,7 +3483,7 @@ pub const Global = struct { |
| 3483 | 3483 | try builder.aliases.ensureUnusedCapacity(builder.gpa, 1); |
| 3484 | 3484 | errdefer comptime unreachable; |
| 3485 | 3485 | const alias: Alias.Index = @fromBackingInt(@intCast(builder.aliases.items.len)); |
| 3486 | builder.aliass.appendAssumeCapacity(.{ .global = global, .aliasee = .none }); | |
| 3486 | builder.aliases.appendAssumeCapacity(.{ .global = global, .aliasee = .none }); | |
| 3487 | 3487 | global.ptr(builder).kind = .{ .alias = alias }; |
| 3488 | 3488 | return alias; |
| 3489 | 3489 | } |
src/codegen/llvm.zig+15-25| ... | ... | @@ -1239,7 +1239,6 @@ pub const Object = struct { |
| 1239 | 1239 | // The name, aliasee, and type will be set within this block. Other properties of the |
| 1240 | 1240 | // alias will be set below. |
| 1241 | 1241 | const alias_global: Builder.Global.Index = global: { |
| 1242 | ||
| 1243 | 1242 | // WORKAROUND (see https://github.com/llvm/llvm-project/issues/213504, https://github.com/llvm/llvm-project/issues/214835) |
| 1244 | 1243 | // For NVPTX, LLVM throws "NVPTX aliasee must be a non-kernel function definition" if we try to alias a kernel |
| 1245 | 1244 | // On AMDGCN, LLVM does not generate an alias for the kernel descriptor symbol on associated functions |
| ... | ... | @@ -1261,33 +1260,24 @@ pub const Object = struct { |
| 1261 | 1260 | }; |
| 1262 | 1261 | // There is an existing global with this name, so we can't just create an alias. We |
| 1263 | 1262 | // need to figure out what to do with the existing global instead. |
| 1264 | switch (existing_global.ptrConst(&o.builder).kind) { | |
| 1265 | .alias => |alias| { | |
| 1266 | // We can just repurpose the existing alias. | |
| 1267 | alias.setAliasee(llvm_global.toConst(), &o.builder); | |
| 1268 | alias.ptrConst(&o.builder).global.ptr(&o.builder).type = llvm_global.typeOf(&o.builder); | |
| 1269 | alias.ptrConst(&o.builder).global.ptr(&o.builder).addr_space = llvm_global.ptrConst(&o.builder).addr_space; | |
| 1270 | break :global existing_global; | |
| 1263 | const alias: Builder.Alias.Index = switch (existing_global.ptrConst(&o.builder).kind) { | |
| 1264 | .alias => |alias| alias: { | |
| 1265 | // The existing alias is from an earlier export, so if `exp` is weak, ignore it. | |
| 1266 | if (exp.opts.linkage == .weak) return; | |
| 1267 | // But otherwise, we can just repurpose the existing alias. | |
| 1268 | break :alias alias; | |
| 1271 | 1269 | }, |
| 1272 | .variable, .function => { | |
| 1273 | // This must be an extern, which is no good to us---we need an alias. The | |
| 1274 | // extern should refer to the value we're exporting, so replace it with the | |
| 1275 | // exported value. That will free up the name for us to create a new alias. | |
| 1276 | // We need to make a new global which is an alias. Replace this existing one | |
| 1277 | // with the target global, making the name available and fixing references | |
| 1278 | // to this global to point to the target. | |
| 1279 | try existing_global.replace(llvm_global, &o.builder); | |
| 1280 | // The name is now free, so create an alias. | |
| 1281 | const alias = try o.builder.addAlias( | |
| 1282 | exp_name, | |
| 1283 | llvm_global_ty, | |
| 1284 | llvm_global.ptrConst(&o.builder).addr_space, | |
| 1285 | llvm_global.toConst(), | |
| 1286 | ); | |
| 1287 | break :global alias.ptrConst(&o.builder).global; | |
| 1270 | .variable, .function => alias: { | |
| 1271 | // This is an extern which our export resolves, so we can simply convert this | |
| 1272 | // global into the alias we want. | |
| 1273 | break :alias try existing_global.toNewAlias(&o.builder); | |
| 1288 | 1274 | }, |
| 1289 | 1275 | .replaced => unreachable, // a replaced global would have lost the name `exp_name` |
| 1290 | } | |
| 1276 | }; | |
| 1277 | alias.setAliasee(llvm_global.toConst(), &o.builder); | |
| 1278 | alias.ptrConst(&o.builder).global.ptr(&o.builder).type = llvm_global_ty; | |
| 1279 | alias.ptrConst(&o.builder).global.ptr(&o.builder).addr_space = llvm_global.ptrConst(&o.builder).addr_space; | |
| 1280 | break :global existing_global; | |
| 1291 | 1281 | }; |
| 1292 | 1282 | |
| 1293 | 1283 | // We need the alias to *not* be `unnamed_addr` to ensure that the alias address equals |
src/link/Elf/ZigObject.zig+11-4| ... | ... | @@ -1871,6 +1871,17 @@ pub fn updateExports( |
| 1871 | 1871 | |
| 1872 | 1872 | for (export_indices) |export_index| { |
| 1873 | 1873 | const exp = export_index.ptr(zcu); |
| 1874 | const exp_name = exp.opts.name.toSlice(&zcu.intern_pool); | |
| 1875 | ||
| 1876 | const global_sym_index = try self.getGlobalSymbol(elf_file, exp_name, null); | |
| 1877 | const global_sym = self.symbol(global_sym_index); | |
| 1878 | const global_esym = &self.symtab.items(.elf_sym)[global_sym.esym_index]; | |
| 1879 | ||
| 1880 | if (global_esym.st_shndx != std.elf.SHN_UNDEF and exp.opts.linkage == .weak) { | |
| 1881 | // The symbol is already defined by a previous export, so ignore this weak export. | |
| 1882 | continue; | |
| 1883 | } | |
| 1884 | ||
| 1874 | 1885 | const metadata = switch (exp.exported) { |
| 1875 | 1886 | .nav => |nav| blk: { |
| 1876 | 1887 | _ = try self.getOrCreateMetadataForNav(zcu, nav); |
| ... | ... | @@ -1902,18 +1913,14 @@ pub fn updateExports( |
| 1902 | 1913 | .weak => elf.STB_WEAK, |
| 1903 | 1914 | }; |
| 1904 | 1915 | const stt_bits: u8 = @as(u4, @truncate(esym.st_info)); |
| 1905 | const exp_name = exp.opts.name.toSlice(&zcu.intern_pool); | |
| 1906 | 1916 | const name_off = try self.strtab.insert(gpa, exp_name); |
| 1907 | const global_sym_index = try self.getGlobalSymbol(elf_file, exp_name, null); | |
| 1908 | 1917 | try metadata.exports.append(gpa, global_sym_index); |
| 1909 | 1918 | |
| 1910 | 1919 | const value = self.symbol(sym_index).value; |
| 1911 | const global_sym = self.symbol(global_sym_index); | |
| 1912 | 1920 | global_sym.value = value; |
| 1913 | 1921 | global_sym.flags.weak = exp.opts.linkage == .weak; |
| 1914 | 1922 | global_sym.version_index = elf_file.default_sym_version; |
| 1915 | 1923 | global_sym.ref = .{ .index = esym_shndx, .file = self.index }; |
| 1916 | const global_esym = &self.symtab.items(.elf_sym)[global_sym.esym_index]; | |
| 1917 | 1924 | global_esym.st_value = @intCast(value); |
| 1918 | 1925 | global_esym.st_shndx = esym.st_shndx; |
| 1919 | 1926 | global_esym.st_info = (stb_bits << 4) | stt_bits; |
test/behavior/extern.zig+17| ... | ... | @@ -66,3 +66,20 @@ test "pass extern function to function" { |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | 68 | export fn an_extern_function() void {} |
| 69 | ||
| 70 | test "@extern binds to strong @export over weak @export" { | |
| 71 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/36986 | |
| 72 | ||
| 73 | const sym_name = "extern_binds_to_strong_export_over_weak_export"; | |
| 74 | ||
| 75 | const weak_0: u8 = 42; | |
| 76 | const strong: u8 = 123; | |
| 77 | const weak_1: u8 = 255; | |
| 78 | ||
| 79 | @export(&weak_0, .{ .name = sym_name, .linkage = .weak }); | |
| 80 | @export(&strong, .{ .name = sym_name, .linkage = .strong }); | |
| 81 | @export(&weak_1, .{ .name = sym_name, .linkage = .weak }); | |
| 82 | ||
| 83 | const extern_ptr = @extern(*const u8, .{ .name = sym_name }); | |
| 84 | try expect(extern_ptr.* == strong); | |
| 85 | } |
test/cases/export_override_libc.zig+2-1| ... | ... | @@ -13,5 +13,6 @@ pub fn main() void { |
| 13 | 13 | } |
| 14 | 14 | |
| 15 | 15 | // run |
| 16 | // target=native | |
| 16 | // target=x86_64-linux-gnu,x86_64-linux-musl | |
| 17 | // backend=selfhosted,llvm | |
| 17 | 18 | // link_libc=true |