https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81033
--- Comment #37 from Iain Sandoe <iains at gcc dot gnu.org> --- Created attachment 44446 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=44446&action=edit Proposed fix for trunk Subject: [PATCH] Fix P81033 for FDEs in partitioned code. Darwin has the ability to split code into "atoms" in the static linker. These can then be re-ordered to optimise the code layout (this is a more fine-grained equivalent of function-sections). This facility requires cooperation of the compiler, assembler and linker. As the assembly stage it's signalled by marking objects as "subsections_vis_symbols" the (expected) default. The rules for splitting code into atoms (if applied strictly) are like this: _linker_visible_labelA: << starts Atom A (section start if there's no linker visible label before the first local one) ... LocalLabelA: <<== belongs to Atom A ... LocalLableB: <<== belongs to Atom A ... LocalLabelC: <<== belongs to Atom A **Even if it has the same address as _linker_visible_labelB** _linker_visible_labelB: << starts Atom B LocalLabelD: <<== belongs to Atom B ===== There are two assemblers in common use for Darwin; one based on an old GAS version (so-called cctools) and one based on the LLVM toolchain. Newer vendor toolchains are based by default on the LLVM toolchain, and older ones on the cctools. The cctools assembler is strict about the atom definitions, the LLVM- based one is apparently more relaxed. ==== The particular issue that affects the FDE generation in partitioned code is this: (section start, or linker-visible symbol makes no difference) LcoldStartN: .... (generally 0-length) _functionN_cold.0: << needed to identify the start of a new atom, << and also to assist in debug on many platforms. ..... then we have in the eh_frame section: ... .quad LcoldStartN - . .long LColdEndN - LcoldStartN Which is intended to point to the start of the code (comes after _functionN_cold.0) But with the cctools assembler, that's not what "LcoldStartN" means, and thus it ends up (usually) pointing to the section start - or worse, to some random place in a previous function). With the LLVM-based toolchain, the assembler appears to allow for the case that LcoldStartN == _functionN_cold.0. BUT (a) it's not guaranteed that this _is_ the case since alignment of _functionN_cold.0 might put nops between LcoldStartN and _functionN_cold.0. (b) It is probably intended to support aliasing and is not intended to change the atom ABI. ** I suppose it’s exploiting a slight ambiguity as to how to approach a zero-sized atom. However, according to the strict def. the local label should be made to exist in a distinct atom - even if that has zero size (and can be laid out wherever we like). So .. --------- For FDEs, the solution is to place LcoldStartN: _after_ _functionN_cold.0 JFTR, one cannot do things like .quad _functionN_cold.0 - . .long LColdEndN - _functionN_cold.0 (i.e. replace the local symbol for the cold section in the FDE by the actual linker-visible one) .. since that produces the case that the second expression cannot be resolved at assembly time and it fails. ===== So this is the simplest patch to ensure that the cold sub-section local symbol appears after the linker-visible one. It moves the output of the symbol from assemble_function_start to the point at which the switch occurs. ==== NOTE that this problem has already been resolved for the first function subsection, since the function start label _myfunction: is followed by LFBN: <<< this is referenced in the first FDE for the function. ===== Since final.c now emits a linker-visible symbol on the switch the one added to emit from the target hook (on text section switch) is both redundant and confuses the linker by having two co-incident symbols. So the patch removes the implementation of the target hook for text sect switch. --- gcc/config/darwin.c | 15 --------------- gcc/config/darwin.h | 4 ---- gcc/final.c | 5 +++++ gcc/varasm.c | 4 ---- 4 files changed, 5 insertions(+), 23 deletions(-)