https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60939
--- Comment #16 from Bernard Ladenthin <bernard.ladenthin at gmail dot com> ---
Follow-up to the patch sent to gcc-patches on 2026-09-05. Everything below
was measured after that mail went out, and two of the items correct or
qualify what it said.
Retested on trunk
-----------------
The submitted message said only "built and tested on powerpc-ibm-aix7.3.1.0
(--disable-bootstrap)" without naming a compiler version. It was 13.3.0
with a rebuilt collect2, not trunk. That gap is now closed: a GCC 17.0.0
built from master on AIX 7.3, with both collect2 variants produced from that
same tree and nothing else differing.
g++.dg/eh/pr60939.C via dg.exp unpatched patched
trunk 17.0.0 3 passes, 3 fails 6 passes, 0 fails
The failing variants are the execution tests in gnu++98, gnu++20 and
gnu++29. Controls: the two collect2 binaries differ, the patched source
contains the new identifier and the original does not, and the patch applies
to master with rc 0. The block it touches is unchanged on master today.
Does this register a frame table twice?
---------------------------------------
This is the obvious objection, and the answer is now measured rather than
argued. With the patch, objects are scanned for frame tables before the
first link, and the first link's output is still scanned afterwards, so the
same table can be seen twice. It is registered once. add_to_list appends,
then walks the list for an equal name and frees the new node on a match.
Keeping collect2's generated file (xgcc -save-temps) on patched trunk:
static void *frame_table[] = {
&x5, /* _GLOBAL__F_fa */
&x6, /* _GLOBAL__F_sink */
0
};
_GLOBAL__F_fa 1
_GLOBAL__F_sink 1
Exactly one entry per translation unit, on the default link and with
-static-libgcc alike. The libgcc frame tables that appear in collect2's
scan log are not in the table -- the archive path still has SCAN_DWEH
stripped, which is the patch behaving as intended.
Does it stop the linker discarding dead code?
---------------------------------------------
The comment being edited says referencing every frame table would "drag all
the corresponding objects even if nothing else is referenced". The concrete
worry is that anchoring a frame table also anchors the function bodies its
FDEs point at. Measured with one translation unit holding a single used
function and 16 unused ones, all -fexceptions, both collect2 binaries built
from the same trunk tree:
unpatched patched
binary size 101626 101626
frame-table entries 2 2
symbols in binary 183 183
dead functions retained 0 0
exit status 0 0
The two binaries differ in four bytes, and those are the letters of the two
-B directory names embedded in the output. Note also that AIX emits one
frame table per translation unit, not one per function, so the unit of
anchoring is the object file -- which is linked unconditionally anyway.
The shared-object and static-archive paths were compared the same way: same
size, no content change, both run. That is what the code predicts, since
the library filter still strips SCAN_DWEH when not building a shared object,
and when building one both filters keep it exactly as before.
A caution for anyone repeating this: collect2 embeds its random temporary
filename in the output, so two links with the same collect2 are not
byte-identical, and unequal -B path or output filename lengths shift sizes
as well. Three separate runs here reported size differences that did not
exist before the names were equalised and a same-arm control was run.
Prior art in this file
----------------------
Worth flagging, because it is adjacent and the connection is not obvious.
Tony Reix, 2018-06, "[PATCH,AIX] Fix -static-libgcc & -static-libgo issues
for AIX" (gcc-patches 2018-06/msg00920) fixed frame tables being registered
twice at runtime -- once by a shared library's initializer and once by the
main program's -- and states that this breaks assumptions in
_Unwind_Find_FDE. That work is upstream: static_obj, static_libs and
aixlazy_flag are all in trunk's collect2.cc today.
That hazard is cross-initializer, so collect2's per-run deduplication cannot
see it, and this patch does not go near it: nothing new is taken from
libraries, and the objects it adds are registered by the same initializer as
before.
One question
------------
The patch's ChangeLog says "PR target/60939", but this bug is filed under
component libgcc. contrib/gcc-changelog only checks that the component is a
known one, so it validated either way. Should the ChangeLog match the
component as filed, or would it be better to recategorise the bug? For a
change in gcc/collect2.cc, "driver" arguably fits better than either.