On ARM64, many symbol references use an adrp+add/ldr pair. When the
references are against a temporary symbol, the references are
normally rewritten as a reference against the start of the section,
plus an immediate offset.
In the relocation for an adrp instruction, the offset from the
referenced symbol is stored in the opcode, which fits a 21 bit
immediate. Thus, if there's an adrp relocation against a temporary
symbol, it ends up out of range if the temporary symbol is further
in than 1 MB in a section.
This addresses the issue reported at
https://bugs.llvm.org/show_bug.cgi?id=52378. It can also be worked
around by using the options -ffunction-sections and -fdata-sections.
By keeping the temporary symbols in the object files (e.g. as the symbol
type IMAGE_SYM_CLASS_LABEL), the relocations only need to store the offset
from this symbol instead of the start of the section.
This roughly matches what MSVC does, where the produced object files
contain lots of temporary label symbols named like $LN<n>.
This does inflate the size of the intermediate object files somewhat,
but makes these relocations much more robust.
clang-format: please reformat the code