From 94c6917f954aa0cfca22b4f2861ba55729362730 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Thu, 5 Nov 2020 18:57:00 +0900 Subject: [PATCH] temporary --- BUGS.md | 69 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/BUGS.md b/BUGS.md index b29bb7ff..4aaf091a 100644 --- a/BUGS.md +++ b/BUGS.md @@ -3,44 +3,47 @@ development of the mold linker. ## GNU IFUNC -A statically-linked "hello world" program mysteriously crashed in -`__libc_start_main` function which is called just after `_start`. +Problem: A statically-linked "hello world" program mysteriously +crashed in `__libc_start_main` function which is called just after +`_start`. -I opened up gdb and found that the program reads a bogus value from -the TLS block. It looks like `memcpy` failed to copy proper data. -After some investigation, I noticed that `memcpy` doesn't copy data at -all but instead returns the address of `__memcpy_avx_unaligned` -function, which is a real `memcpy` function optimized for machines -with AVX registers. +Investigation: I opened up gdb and found that the program reads a +bogus value from a TLS block. It looks like `memcpy` failed to copy +proper data there. After some investigation, I noticed that `memcpy` +doesn't copy data at all but instead returns the address of +`__memcpy_avx_unaligned` function, which is a real `memcpy` function +optimized for machines with the AVX registers. -It turned out the odd issue was caused by the GNU IFUNC mechanism. -That is, if a function symbol has the type `STT_GNU_IFUNC`, the -function does not do what its name suggests to do but instead returns -a pointer to a function that does the actual job. In this case, -`memcpy` is an IFUNC function, and it returns an address of -`__memcpy_avx_unaligned`. +This odd issue was caused by the GNU IFUNC mechanism. That is, if a +function symbol has type `STT_GNU_IFUNC`, the function does not do +what its name suggests to do but instead returns a pointer to a +function that does the actual job. In this case, `memcpy` is an IFUNC +function, and it returns an address of `__memcpy_avx_unaligned` which +is a real `memcpy` function. -IFUNC function addresses are stored to `.got` section. The dynamic -loader executes all IFUNC functions at startup and replace their GOT -entries with their return values. This mechanism allows programs to -choose the best implementation among variants of the same function at -runtime based on the machine info. +IFUNC function addresses are stored to `.got` section in an ELF +executable. The dynamic loader executes all IFUNC functions at +startup and replace their GOT entries with their return values. This +mechanism allows programs to choose the best implementation among +variants of the same function at runtime based on the machine info. If a program is statically-linked, there's no dynamic loader that -rewrites its GOT entries. Therefore, if a program is +rewrites the GOT entries. Therefore, if a program is statically-linked, a libc's startup routine does that on behalf of the -dynamic loader. Concretely, the startup routine interprets all dynamic -relocations between `__rela_iplt_start` and `__rela_iplt_start` symbols. -It is linker's responsibility to mark the beginning and the ending of -a `.rela.dyn` section with the symbols, so that the startup routine -can find it. +dynamic loader. Concretely, a startup routine interprets all dynamic +relocations between `__rela_iplt_start` and `__rela_iplt_start` +symbols. It is linker's responsibility to emit dynamic relocations +for IFUNC symbols even if it is linking a statically-linked program +and mark the beginning and the ending of a `.rela.dyn` section with +the symbols, so that the startup routine can find the relocations. -The bug was my linker didn't define these symbols. Since these symbols -are weak, they are initialized to zero, and from the point of the -initializer function, there's no dynamic entries between -`__rela_iplt_start` and `__rela_iplt_start` symbols. That left GOT -entries for IFUNC symbols. If you call one of the functions, it don't -do what it should do but instead returns a pointer that its job. +The bug was my linker didn't define `__rela_iplt_start` and +`__rela_iplt_stop` symbols. Since these symbols are weak, they are +initialized to zero. From the point of the initializer function, +there's no dynamic entries between `__rela_iplt_start` and +`__rela_iplt_start` symbols. That left GOT entries for IFUNC symbols +untouched. -The proper fix was to define the linker-synthesized symbols. I did -that, and the bug was fixed. +The proper fix was to emit dynamic relocations for IFUNC symbols and +define the linker-synthesized symbols. I did that, and the bug was +fixed.