From 53b2f36bf6aa939feab6f82f05d7dad52f82660d Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Mon, 25 Mar 2019 12:08:53 +0000 Subject: [PATCH] AArch64: Fix disassembler bug with out-of-order sections The AArch64 disassembler has an optimization that it uses to reduce the amount it has to search for mapping symbols during disassembly. This optimization assumes that sections are listed in the section header in monotonic increasing VMAs. However this is not a requirement for the ELF specification. Because of this when such "out of order" sections occur the disassembler would pick the wrong mapping symbol to disassemble the section with. This fixes it by explicitly passing along the stop offset for the current disassembly glob and when this changes compared to the previous one we've seen the optimization won't be performed. In effect this restarts the search from a well defined starting point. Usually the symbol's address. The existing stop_vma can't be used for this as it is allowed to be unset and setting this unconditionally would change the semantics of this field. binutils/ChangeLog: * objdump.c (disassemble_bytes): Pass stop_offset. * testsuite/binutils-all/aarch64/out-of-order.T: New test. * testsuite/binutils-all/aarch64/out-of-order.d: New test. * testsuite/binutils-all/aarch64/out-of-order.s: New test. include/ChangeLog: * dis-asm.h (struct disassemble_info): Add stop_offset. opcodes/ChangeLog: * aarch64-dis.c (last_stop_offset): New. (print_insn_aarch64): Use stop_offset. --- binutils/ChangeLog | 7 +++++ binutils/objdump.c | 1 + .../binutils-all/aarch64/out-of-order.T | 14 ++++++++++ .../binutils-all/aarch64/out-of-order.d | 27 ++++++++++++++++++ .../binutils-all/aarch64/out-of-order.s | 28 +++++++++++++++++++ include/ChangeLog | 4 +++ include/dis-asm.h | 6 ++++ opcodes/ChangeLog | 5 ++++ opcodes/aarch64-dis.c | 7 ++++- 9 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 binutils/testsuite/binutils-all/aarch64/out-of-order.T create mode 100644 binutils/testsuite/binutils-all/aarch64/out-of-order.d create mode 100644 binutils/testsuite/binutils-all/aarch64/out-of-order.s diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 6fa4bf48e4..121c54d991 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,10 @@ +2019-03-25 Tamar Christina + + * objdump.c (disassemble_bytes): Pass stop_offset. + * testsuite/binutils-all/aarch64/out-of-order.T: New test. + * testsuite/binutils-all/aarch64/out-of-order.d: New test. + * testsuite/binutils-all/aarch64/out-of-order.s: New test. + 2019-03-19 Nick Clifton PR 24360 diff --git a/binutils/objdump.c b/binutils/objdump.c index 79aed757ae..d80b3f5a88 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -1991,6 +1991,7 @@ disassemble_bytes (struct disassemble_info * inf, disassembling code of course, and when -D is in effect. */ inf->stop_vma = section->vma + stop_offset; + inf->stop_offset = stop_offset; octets = (*disassemble_fn) (section->vma + addr_offset, inf); inf->stop_vma = 0; diff --git a/binutils/testsuite/binutils-all/aarch64/out-of-order.T b/binutils/testsuite/binutils-all/aarch64/out-of-order.T new file mode 100644 index 0000000000..489ae80190 --- /dev/null +++ b/binutils/testsuite/binutils-all/aarch64/out-of-order.T @@ -0,0 +1,14 @@ +ENTRY(v1) +SECTIONS +{ + . = 0xffe00000; + .global : { *(.global) } + . = 0x4018280; + .func2 : { *(.func2) } + . = 0x4005000; + .func1 : { *(.func1) } + . = 0x4015000; + .func3 : { *(.func3) } + .data : { *(.data) } + .rodata : { *(.rodata) } +} \ No newline at end of file diff --git a/binutils/testsuite/binutils-all/aarch64/out-of-order.d b/binutils/testsuite/binutils-all/aarch64/out-of-order.d new file mode 100644 index 0000000000..410f37f68e --- /dev/null +++ b/binutils/testsuite/binutils-all/aarch64/out-of-order.d @@ -0,0 +1,27 @@ +#PROG: objcopy +#ld: -T out-of-order.T +#objdump: -d +#name: Check if disassembler can handle sections in different order than header + +.*: +file format .*aarch64.* + +Disassembly of section \.func2: + +0000000004018280 <\.func2>: + 4018280: 8b010000 add x0, x0, x1 + +Disassembly of section \.func1: + +0000000004005000 : + 4005000: 8b010000 add x0, x0, x1 + 4005004: 00000000 \.word 0x00000000 + +Disassembly of section \.func3: + +0000000004015000 <\.func3>: + 4015000: 8b010000 add x0, x0, x1 + 4015004: 8b010000 add x0, x0, x1 + 4015008: 8b010000 add x0, x0, x1 + 401500c: 8b010000 add x0, x0, x1 + 4015010: 8b010000 add x0, x0, x1 + 4015014: 00000000 \.word 0x00000000 diff --git a/binutils/testsuite/binutils-all/aarch64/out-of-order.s b/binutils/testsuite/binutils-all/aarch64/out-of-order.s new file mode 100644 index 0000000000..6c52e857df --- /dev/null +++ b/binutils/testsuite/binutils-all/aarch64/out-of-order.s @@ -0,0 +1,28 @@ + .text + .global v1 + .section .func1,"ax",@progbits + .type v1 %function + .size v1, 4 +v1: + add x0, x0, x1 + .word 0 + + .section .func2,"ax",@progbits + add x0, x0, x1 + + .section .func3,"ax",@progbits + add x0, x0, x1 + add x0, x0, x1 + add x0, x0, x1 + add x0, x0, x1 + add x0, x0, x1 + .word 0 + + .data + .section .global,"aw",@progbits + .xword 1 + .xword 1 + .xword 1 + + .section .rodata + .word 4 diff --git a/include/ChangeLog b/include/ChangeLog index b4a0907e80..ae79b9f47f 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,7 @@ +2019-03-25 Tamar Christina + + * dis-asm.h (struct disassemble_info): Add stop_offset. + 2019-03-13 Sudakshina Das * elf/aarch64.h (DT_AARCH64_PAC_PLT): New. diff --git a/include/dis-asm.h b/include/dis-asm.h index 22c593ece6..4e1263c90e 100644 --- a/include/dis-asm.h +++ b/include/dis-asm.h @@ -221,6 +221,12 @@ typedef struct disassemble_info file being disassembled. */ bfd_vma stop_vma; + /* The end range of the current range being disassembled. This is required + in order to notify the disassembler when it's currently handling a + different range than it was before. This prevent unsafe optimizations when + disassembling such as the way mapping symbols are found on AArch64. */ + bfd_vma stop_offset; + } disassemble_info; /* This struct is used to pass information about valid disassembler diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 204c008ab4..81fe9f00b2 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,8 @@ +2019-03-25 Tamar Christina + + * aarch64-dis.c (last_stop_offset): New. + (print_insn_aarch64): Use stop_offset. + 2019-03-19 H.J. Lu PR gas/24359 diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c index 4c31f57451..fc7e95d066 100644 --- a/opcodes/aarch64-dis.c +++ b/opcodes/aarch64-dis.c @@ -37,6 +37,7 @@ enum map_type static enum map_type last_type; static int last_mapping_sym = -1; +static bfd_vma last_stop_offset = 0; static bfd_vma last_mapping_addr = 0; /* Other options */ @@ -3333,7 +3334,10 @@ print_insn_aarch64 (bfd_vma pc, /* Start scanning at the start of the function, or wherever we finished last time. */ n = info->symtab_pos + 1; - if (n < last_mapping_sym) + /* If the last stop offset is different from the current one it means we + are disassembling a different glob of bytes. As such the optimization + would not be safe and we should start over. */ + if (n < last_mapping_sym && info->stop_offset == last_stop_offset) n = last_mapping_sym; /* Scan up to the location being disassembled. */ @@ -3370,6 +3374,7 @@ print_insn_aarch64 (bfd_vma pc, last_mapping_sym = last_sym; last_type = type; + last_stop_offset = info->stop_offset; /* Look a little bit ahead to see if we should print out less than four bytes of data. If there's a symbol, -- 2.34.1