Re: [PATCH] perf symbols: Fix plt entry calculation for ARM and AARCH64

From: Namhyung Kim
Date: Mon Jun 05 2017 - 21:47:59 EST


On Mon, Jun 5, 2017 at 9:34 AM, Li Bin <huawei.libin@xxxxxxxxxx> wrote:
> On x86, the plt header size is as same as the plt entry size, and
> can be identified from shdr's sh_entsize of the plt.
> But we cann't assume that the sh_entsize of the plt shdr is always
> the plt entry size in all architecture, and the plt header size may
> be not as same as the plt entry size in some architecure.
>
> On ARM, the plt header size is 20 bytes and the plt entry size is 12
> bytes(don't consider the FOUR_WORD_PLT case)
> that refer to the binutils implementation.
> plt section is as follows:
>
> Disassembly of section .plt:
> 000004a0 <__cxa_finalize@plt-0x14>:
> 4a0: e52de004 push {lr} ; (str lr, [sp, #-4]!)
> 4a4: e59fe004 ldr lr, [pc, #4] ; 4b0 <_init+0x1c>
> 4a8: e08fe00e add lr, pc, lr
> 4ac: e5bef008 ldr pc, [lr, #8]!
> 4b0: 00008424 .word 0x00008424
>
> 000004b4 <__cxa_finalize@plt>:
> 4b4: e28fc600 add ip, pc, #0, 12
> 4b8: e28cca08 add ip, ip, #8, 20 ; 0x8000
> 4bc: e5bcf424 ldr pc, [ip, #1060]! ; 0x424
>
> 000004c0 <printf@plt>:
> 4c0: e28fc600 add ip, pc, #0, 12
> 4c4: e28cca08 add ip, ip, #8, 20 ; 0x8000
> 4c8: e5bcf41c ldr pc, [ip, #1052]! ; 0x41c
>
> On AARCH64, the plt header size is 32 bytes and the plt entry size is
> 16 bytes.
> plt section is as follows:
>
> Disassembly of section .plt:
> 0000000000000560 <__cxa_finalize@plt-0x20>:
> 560: a9bf7bf0 stp x16, x30, [sp,#-16]!
> 564: 90000090 adrp x16, 10000 <__FRAME_END__+0xf8a8>
> 568: f944be11 ldr x17, [x16,#2424]
> 56c: 9125e210 add x16, x16, #0x978
> 570: d61f0220 br x17
> 574: d503201f nop
> 578: d503201f nop
> 57c: d503201f nop
>
> 0000000000000580 <__cxa_finalize@plt>:
> 580: 90000090 adrp x16, 10000 <__FRAME_END__+0xf8a8>
> 584: f944c211 ldr x17, [x16,#2432]
> 588: 91260210 add x16, x16, #0x980
> 58c: d61f0220 br x17
>
> 0000000000000590 <__gmon_start__@plt>:
> 590: 90000090 adrp x16, 10000 <__FRAME_END__+0xf8a8>
> 594: f944c611 ldr x17, [x16,#2440]
> 598: 91262210 add x16, x16, #0x988
> 59c: d61f0220 br x17
>
> NOTES:
> In addition to ARM and AARCH64, other architectures, such as
> s390/alpha/mips/parisc/poperpc/sh/sparc/xtensa also need to consider
> this issue.
>
> Signed-off-by: Li Bin <huawei.libin@xxxxxxxxxx>

I don't know other archs, but this change looks ok to me..

Acked-by: Namhyung Kim <namhyung@xxxxxxxxxx>

Thanks,
Namhyung


> ---
> tools/perf/util/symbol-elf.c | 27 ++++++++++++++++++++++-----
> 1 file changed, 22 insertions(+), 5 deletions(-)
>
> diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
> index e7ee47f..1bccf71 100644
> --- a/tools/perf/util/symbol-elf.c
> +++ b/tools/perf/util/symbol-elf.c
> @@ -259,7 +259,7 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *
> {
> uint32_t nr_rel_entries, idx;
> GElf_Sym sym;
> - u64 plt_offset;
> + u64 plt_offset, plt_header_size, plt_entry_size;
> GElf_Shdr shdr_plt;
> struct symbol *f;
> GElf_Shdr shdr_rel_plt, shdr_dynsym;
> @@ -326,6 +326,23 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *
>
> nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
> plt_offset = shdr_plt.sh_offset;
> + switch (ehdr.e_machine) {
> + case EM_ARM:
> + plt_header_size = 20;
> + plt_entry_size = 12;
> + break;
> +
> + case EM_AARCH64:
> + plt_header_size = 32;
> + plt_entry_size = 16;
> + break;
> +
> + default: /* FIXME: s390/alpha/mips/parisc/poperpc/sh/sparc/xtensa need to be checked */
> + plt_header_size = shdr_plt.sh_entsize;
> + plt_entry_size = shdr_plt.sh_entsize;
> + break;
> + }
> + plt_offset += plt_header_size;
>
> if (shdr_rel_plt.sh_type == SHT_RELA) {
> GElf_Rela pos_mem, *pos;
> @@ -335,7 +352,6 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *
> const char *elf_name = NULL;
> char *demangled = NULL;
> symidx = GELF_R_SYM(pos->r_info);
> - plt_offset += shdr_plt.sh_entsize;
> gelf_getsym(syms, symidx, &sym);
>
> elf_name = elf_sym__name(&sym, symstrs);
> @@ -346,11 +362,12 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *
> "%s@plt", elf_name);
> free(demangled);
>
> - f = symbol__new(plt_offset, shdr_plt.sh_entsize,
> + f = symbol__new(plt_offset, plt_entry_size,
> STB_GLOBAL, sympltname);
> if (!f)
> goto out_elf_end;
>
> + plt_offset += plt_entry_size;
> symbols__insert(&dso->symbols[map->type], f);
> ++nr;
> }
> @@ -361,7 +378,6 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *
> const char *elf_name = NULL;
> char *demangled = NULL;
> symidx = GELF_R_SYM(pos->r_info);
> - plt_offset += shdr_plt.sh_entsize;
> gelf_getsym(syms, symidx, &sym);
>
> elf_name = elf_sym__name(&sym, symstrs);
> @@ -372,11 +388,12 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *
> "%s@plt", elf_name);
> free(demangled);
>
> - f = symbol__new(plt_offset, shdr_plt.sh_entsize,
> + f = symbol__new(plt_offset, plt_entry_size,
> STB_GLOBAL, sympltname);
> if (!f)
> goto out_elf_end;
>
> + plt_offset += plt_entry_size;
> symbols__insert(&dso->symbols[map->type], f);
> ++nr;
> }
> --
> 1.7.12.4
>