[PATCH 19/32] x86/vdso2c: Align LOCAL symbols between vdso{-timens,}.so
From: Dmitry Safonov <hidden>
Date: 2019-02-06 00:12:55
Also in:
lkml
Subsystem:
the rest, x86 architecture (32-bit and 64-bit), x86 entry code, x86 vdso · Maintainers:
Linus Torvalds, Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, Andy Lutomirski
Align not only VDSO entries as on timens VDSO, but also addresses of
local functions. Otherwise, ld will put them after everything else
into *(.text*). That will result in common VDSO size bigger than
timens VDSO size (sic!).
Unfortunately, filtering by STB_WEAK doesn't work for ia32 VDSO:
by some reason gcc transforms weak symbols into local symbols in .so,
i.e.:
27: 00000000 219 FUNC WEAK DEFAULT 12 clock_gettime
29: 00000000 95 FUNC WEAK DEFAULT 14 gettimeofday
32: 00000000 40 FUNC WEAK DEFAULT 16 time
become:
20: 000006e0 219 FUNC LOCAL DEFAULT 12 clock_gettime
31: 000007c0 95 FUNC LOCAL DEFAULT 12 gettimeofday
33: 00000820 40 FUNC LOCAL DEFAULT 12 time
that results in the same align for two functions in .entries file:
. = ABSOLUTE(0x6e0);
*(.text.__vdso_clock_gettime*)
. = ABSOLUTE(0x6e0);
*(.text.clock_gettime*)
As result, ld becomes a very sad animal and refuses to cooperate:
ld:arch/x86/entry/vdso/vdso32/vdso32.lds:339 cannot move location counter backwards (from 0000000000000762 to 00000000000006e0)
Align local functions on VDSO to timens VDSO and filter weak functions
from .lds script.
Signed-off-by: Dmitry Safonov <redacted>
---
arch/x86/entry/vdso/vdso2c.h | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/arch/x86/entry/vdso/vdso2c.h b/arch/x86/entry/vdso/vdso2c.h
index 50566dd94451..7096710140fe 100644
--- a/arch/x86/entry/vdso/vdso2c.h
+++ b/arch/x86/entry/vdso/vdso2c.h@@ -15,7 +15,7 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, unsigned long mapping_size; ELF(Ehdr) *hdr = (ELF(Ehdr) *)raw_addr; unsigned int i, syms_nr; - unsigned long j; + unsigned long j, last_entry_addr; ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr, *alt_sec = NULL; ELF(Dyn) *dyn = 0, *dyn_end = 0;
@@ -121,7 +121,7 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, if (!out_entries_lds) continue; - if (ELF_FUNC(ST_BIND, sym->st_info) != STB_GLOBAL) + if (ELF_FUNC(ST_BIND, sym->st_info) == STB_WEAK) continue; if (ELF_FUNC(ST_TYPE, sym->st_info) != STT_FUNC)
@@ -134,8 +134,19 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, qsort(entries, next_entry - entries, sizeof(*entries), entry_addr_cmp); + last_entry_addr = -1UL; while (next_entry != entries && out_entries_lds) { next_entry--; + + /* + * Unfortunately, WEAK symbols from objects are resoved + * into LOCAL symbols on ia32. Filter them here, as + * linker wouldn't like aligning the same symbol twice. + */ + if (last_entry_addr == next_entry->addr) + continue; + last_entry_addr = next_entry->addr; + fprintf(out_entries_lds, "\t\t. = ABSOLUTE(%#lx);\n\t\t*(.text.%s*)\n", next_entry->addr, next_entry->name); }
--
2.20.1