diff options
author | Romain Geissler <romain.geissler@amadeus.com> | 2021-01-28 13:41:20 +0000 |
---|---|---|
committer | Dave Watson <dade.watson@gmail.com> | 2021-02-17 09:13:55 -0800 |
commit | 3ad1017bdb3508cb0d4cce4d6e3dccd4ab71816e (patch) | |
tree | 7f5be2958886196d526d3a805c7bb33ef687f0ad | |
parent | 4ed2ac7c9ff3b2be0baed294d79cdbc481a53296 (diff) | |
download | libunwind-3ad1017bdb3508cb0d4cce4d6e3dccd4ab71816e.tar.gz |
Fix elf get_load_offset when the binary was linked by lld, which defines read/executable program header offsets not always aligned on a page size.
For example, the same library, linked with ld.bfd will show these PT_LOAD mappings:
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x000000000002b3d0 0x000000000002b3d0 R 0x1000
LOAD 0x000000000002c000 0x000000000002c000 0x000000000002c000
0x000000000001b729 0x000000000001b729 R E 0x1000
LOAD 0x0000000000048000 0x0000000000048000 0x0000000000048000
0x000000000000fb17 0x000000000000fb17 R 0x1000
LOAD 0x0000000000057fb0 0x0000000000058fb0 0x0000000000058fb0
0x00000000000010b0 0x0000000000001508 RW 0x1000
while ld.lld, from the very same .o files, will link it like this:
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x000000000003b32c 0x000000000003b32c R 0x1000
LOAD 0x000000000003b330 0x000000000003c330 0x000000000003c330
0x000000000001b740 0x000000000001b740 R E 0x1000
LOAD 0x0000000000056a70 0x0000000000058a70 0x0000000000058a70
0x0000000000001050 0x0000000000001050 RW 0x1000
LOAD 0x0000000000057ac0 0x000000000005aac0 0x000000000005aac0
0x0000000000000060 0x00000000000004b3 RW 0x1000
Failure to identify the load_offset from iterating the program header lead to later being unable
to find the correct proc_info for a given symbol.
-rw-r--r-- | src/elfxx.c | 7 |
1 files changed, 6 insertions, 1 deletions
diff --git a/src/elfxx.c b/src/elfxx.c index 2589a3d4..c6baa098 100644 --- a/src/elfxx.c +++ b/src/elfxx.c @@ -165,12 +165,17 @@ elf_w (get_load_offset) (struct elf_image *ei, unsigned long segbase, Elf_W (Ehdr) *ehdr; Elf_W (Phdr) *phdr; int i; + // mapoff is obtained from mmap informations, so is always aligned on a page size. + // PT_LOAD program headers p_offset however is not guaranteed to be aligned on a + // page size, ld.lld generate libraries where this is not the case. So we must + // make sure we compare both values with the same alignment. + unsigned long pagesize_aligment_mask = ~(((unsigned long)getpagesize()) - 1UL); ehdr = ei->image; phdr = (Elf_W (Phdr) *) ((char *) ei->image + ehdr->e_phoff); for (i = 0; i < ehdr->e_phnum; ++i) - if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff) + if (phdr[i].p_type == PT_LOAD && (phdr[i].p_offset & pagesize_aligment_mask) == mapoff) { offset = segbase - phdr[i].p_vaddr; break; |