https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126841
--- Comment #5 from Longjun Luo <luolongjuna at gmail dot com> ---
One additional observation: this is not limited to identical function bodies
being placed together. The retained section name can also co-locate a
privatized local function with an unrelated exported one.
a.c:
static int same_fn(int x) { return x * 33 + 7; }
int (*a_cb)(int) = same_fn;
b.c:
static int same_fn(int x) { return x * 33 + 7; }
int (*b_cb)(int) = same_fn;
d.c:
int same_fn(int x) { return x - 1; }
gcc -O2 -flto -ffunction-sections -fPIC -c a.c -o a.o
gcc -O2 -flto -ffunction-sections -fPIC -c b.c -o b.o
gcc -O2 -flto -ffunction-sections -fPIC -c d.c -o d.o
gcc -shared -O2 -flto -ffunction-sections -save-temps=obj \
a.o b.o d.o -o r.so
gcc -c r.so.ltrans0.ltrans.s -o ltrans-native.o
readelf -Ws ltrans-native.o:
3: 0000000000000000 10 FUNC LOCAL DEFAULT 4 same_fn.lto_priv.0
5: 0000000000000000 10 FUNC LOCAL DEFAULT 5 same_fn.lto_priv.1
6: 0000000000000010 4 FUNC GLOBAL DEFAULT 5 same_fn
readelf -SW ltrans-native.o:
[4] .text.same_fn.lto_priv.0 PROGBITS ... size 0x0a
[5] .text.same_fn PROGBITS ... size 0x14
Thus .text.same_fn contains the file-local same_fn.lto_priv.1 at offset 0x0
and the exported same_fn at offset 0x10. They differ in linkage, assembler
name, and implementation. Although the section name exactly matches the
exported function, the private body occupies its beginning. As a result, a
linker script rule such as *(.text.same_fn), or any other section-name based
selection, necessarily selects both functions; they can no longer be placed
or discarded as independent function sections.
For comparison, the analogous variable case behaves differently. Three
translation units, each containing
static int same_var = 42;
int *a_ptr = &same_var; /* b_ptr and c_ptr in the other two */
and built the same way with -fdata-sections added emit
.data.same_var.lto_priv.0
.data.same_var.lto_priv.1
.data.same_var.lto_priv.2
so the emitted data-section names track the privatized assembler names.