Re: [PATCH] objtool: ignore .L prefixed local symbols

From: Fangrui Song
Date: Fri Feb 14 2020 - 13:05:37 EST


I know little about objtool, but if it may be used by other
architectures, hope the following explanations don't appear to be too
off-topic:)

On 2020-02-14, Arvind Sankar wrote:
On Thu, Feb 13, 2020 at 11:20:55AM -0800, Fangrui Song wrote:
On 2020-02-13, Nick Desaulniers wrote:
>Top of tree LLVM has optimizations related to
>-fno-semantic-interposition to avoid emitting PLT relocations for
>references to symbols located in the same translation unit, where it
>will emit "local symbol" references.
>
>Clang builds fall back on GNU as for assembling, currently. It appears a
>bug in GNU as introduced around 2.31 is keeping around local labels in
>the symbol table, despite the documentation saying:
>
>"Local symbols are defined and used within the assembler, but they are
>normally not saved in object files."

If you can reword the paragraph above mentioning the fact below without being
more verbose, please do that.

If the reference is within the same section which defines the .L symbol,
there is no outstanding relocation. If the reference is outside the
section, there will be an R_X86_64_PLT32 referencing .L


Can you describe what case the clang change is supposed to optimize?
AFAICT, it kicks in when the symbol is known by the compiler to be local
to the DSO and defined in the same translation unit.

But then there are two cases:
(a) we have call foo, where foo is defined in the same section as the
call instruction. In this case the assembler should be able to fully
resolve foo and not generate any relocation, regardless of whether foo
is global or local.

If foo is STB_GLOBAL or STB_WEAK, the assembler cannot fully resolve a
reference to foo in the same section, unless the assembler can assume
(the codegen tells it) the call to foo cannot be interposed by another
foo definition at runtime.

(b) we have call foo, where foo is defined in a different section from
the call instruction. In this case the assembler must generate a
relocation regardless of whether foo is global or local, and the linker
should eliminate it.
In what case does does replacing call foo with call .Lfoo$local help?

For -fPIC -fno-semantic-interposition, the assembly emitter can perform
the following optimization:

void foo() {}
void bar() { foo(); }

.globl foo, bar
foo:
.Lfoo$local:
ret
bar:
call foo --> call .Lfoo$local
ret

call foo generates an R_X86_64_PLT32. In a -shared link, it creates an
unneeded PLT entry for foo.

call .Lfoo$local generates an R_X86_64_PLT32. In a -shared link, .Lfoo$local is
non-preemptible => no PLT entry is created.

For -fno-PIC and -fPIE, the final link is expected to be -no-pie or
-pie. This optimization does not save anything, because PLT entries will
not be generated. With clang's integrated assembler, it may increase the
number of STT_SECTION symbols (because .Lfoo$local will be turned to a
STT_SECTION relative relocation), but the size increase is very small.


I want to teach clang -fPIC to use -fno-semantic-interposition by
default. (It is currently an LLVM optimization, not realized in clang.)
clang traditionally makes various -fno-semantic-interposition
assumptions and can perform interprocedural optimizations even if the
strict ELF rule disallows them.