diff options
author | Benjamin Teoh <Benjamin.Teoh@arm.com> | 2023-12-06 17:20:40 +0000 |
---|---|---|
committer | Alex Coplan <alex.coplan@arm.com> | 2023-12-06 18:40:59 +0000 |
commit | b107ba426e4559789d7358691a066ba6a92e86bb (patch) | |
tree | fc67689c0f06a3e99ac162fcdade0e53283001a1 | |
parent | 690199d5d4180f287074f2976a12d2df1e415d67 (diff) | |
download | gdb-b107ba426e4559789d7358691a066ba6a92e86bb.zip gdb-b107ba426e4559789d7358691a066ba6a92e86bb.tar.gz gdb-b107ba426e4559789d7358691a066ba6a92e86bb.tar.bz2 |
morello/disassembler: Fixed objdump of adrp inst with negative offset
When an adrp instruction references a symbol that is more than a page
in memory behind the instruction, it would have a negative offset.
An example of this is:
foo:
nop
.zero 4096
adrp c0, foo
where adrp references 'foo' that is more than a page in memory behind
it.
In the case where the offset is negative, when translating from its
binary format, the offset was seen as an unsigned integer, which
caused a spurious high bit set in the resolved address in the adrp
instruction like in:
0000000000400078 <foo>:
400078: d503201f nop
...
40107c: f0ffffe0 adrp c0, 100400000 <__bss_end__+0xfffeeff8>
There was an issue with how the imm field of the adrp instruction was
extracted in `aarch64_ext_imm`. The value was not sign extended
correctly for capability mode targets. This was caused by the imm
field having its `P` bit being removed before the sign extension,
which is exclusive to 64-bit capability targets. This was remedied
by shortening the width of the imm field before sign extending the
imm value, resulting in:
0000000000400078 <foo>:
400078: d503201f nop
...
40107c: f0ffffe0 adrp c0, 400000 <foo-0x78>
-rw-r--r-- | binutils/testsuite/binutils-all/aarch64/disas-adrp-neg-ofs.d | 15 | ||||
-rw-r--r-- | binutils/testsuite/binutils-all/aarch64/disas-adrp-neg-ofs.s | 5 | ||||
-rw-r--r-- | opcodes/aarch64-dis.c | 4 |
3 files changed, 23 insertions, 1 deletions
diff --git a/binutils/testsuite/binutils-all/aarch64/disas-adrp-neg-ofs.d b/binutils/testsuite/binutils-all/aarch64/disas-adrp-neg-ofs.d new file mode 100644 index 0000000..9f2e2a5 --- /dev/null +++ b/binutils/testsuite/binutils-all/aarch64/disas-adrp-neg-ofs.d @@ -0,0 +1,15 @@ +#name: disas-adrp-neg-ofs +#source: disas-adrp-neg-ofs.s +#as: -march=morello+c64 +#ld: --section-start .text=0x400000 +#objdump: -D + +.*: +file format .*aarch64.* + + +Disassembly of section .text: + +0000000000400000 <_start>: + 400000: d503201f nop + ... + 401004: f0ffffe0 adrp c0, 400000 <_start> diff --git a/binutils/testsuite/binutils-all/aarch64/disas-adrp-neg-ofs.s b/binutils/testsuite/binutils-all/aarch64/disas-adrp-neg-ofs.s new file mode 100644 index 0000000..875a9e2 --- /dev/null +++ b/binutils/testsuite/binutils-all/aarch64/disas-adrp-neg-ofs.s @@ -0,0 +1,5 @@ + .global _start +_start: + nop + .zero 4096 + adrp c0, _start diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c index a1778b4..32a40f0 100644 --- a/opcodes/aarch64-dis.c +++ b/opcodes/aarch64-dis.c @@ -676,6 +676,7 @@ aarch64_ext_imm (const aarch64_operand *self, aarch64_opnd_info *info, aarch64_operand_error *errors ATTRIBUTE_UNUSED) { uint64_t imm; + unsigned width_ofs = 1; imm = extract_all_fields (self, code); @@ -688,10 +689,11 @@ aarch64_ext_imm (const aarch64_operand *self, aarch64_opnd_info *info, return FALSE; imm &= (1UL << 20) - 1; + width_ofs++; } if (operand_need_sign_extension (self)) - imm = sign_extend (imm, get_operand_fields_width (self) - 1); + imm = sign_extend (imm, get_operand_fields_width (self) - width_ofs); if (operand_need_shift_by_two (self)) imm <<= 2; |