From 27c72c555a3e5cb170703e3820a1f0ce25fc3e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 24 Aug 2024 22:42:57 +0200 Subject: [PATCH] glibc: Fix an edge case leading to duplicate stub symbols. Closes #20376. Closes #21076. --- src/glibc.zig | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/glibc.zig b/src/glibc.zig index 2849883e04..7042f9c102 100644 --- a/src/glibc.zig +++ b/src/glibc.zig @@ -854,6 +854,23 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi var opt_symbol_name: ?[]const u8 = null; var versions_buffer: [32]u8 = undefined; var versions_len: usize = undefined; + + // There can be situations where there are multiple inclusions for the same symbol with + // partially overlapping versions, due to different target lists. For example: + // + // lgammal: + // library: libm.so + // versions: 2.4 2.23 + // targets: ... powerpc64-linux-gnu s390x-linux-gnu + // lgammal: + // library: libm.so + // versions: 2.2 2.23 + // targets: sparc64-linux-gnu s390x-linux-gnu + // + // If we don't handle this, we end up writing the default `lgammal` symbol for version 2.33 + // twice, which causes a "duplicate symbol" assembler error. + var versions_written = std.AutoArrayHashMap(Version, void).init(arena); + while (sym_i < fn_inclusions_len) : (sym_i += 1) { const sym_name = opt_symbol_name orelse n: { const name = mem.sliceTo(metadata.inclusions[inc_i..], 0); @@ -907,6 +924,10 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi } } } + + versions_written.clearRetainingCapacity(); + try versions_written.ensureTotalCapacity(versions_len); + { var ver_buf_i: u8 = 0; while (ver_buf_i < versions_len) : (ver_buf_i += 1) { @@ -917,6 +938,9 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi // _Exit_2_2_5: const ver_index = versions_buffer[ver_buf_i]; const ver = metadata.all_versions[ver_index]; + + if (versions_written.getOrPutAssumeCapacity(ver).found_existing) continue; + // Default symbol version definition vs normal symbol version definition const want_default = chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index; const at_sign_str: []const u8 = if (want_default) "@@" else "@"; @@ -1066,6 +1090,10 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi } } } + + versions_written.clearRetainingCapacity(); + try versions_written.ensureTotalCapacity(versions_len); + { var ver_buf_i: u8 = 0; while (ver_buf_i < versions_len) : (ver_buf_i += 1) { @@ -1077,6 +1105,9 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi // environ_2_2_5: const ver_index = versions_buffer[ver_buf_i]; const ver = metadata.all_versions[ver_index]; + + if (versions_written.getOrPutAssumeCapacity(ver).found_existing) continue; + // Default symbol version definition vs normal symbol version definition const want_default = chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index; const at_sign_str: []const u8 = if (want_default) "@@" else "@";