[llvm-objdump][ARM] Find ELF file PLT entries for arm, thumb (#130764)

This implements arm, armeb, thumb, thumbeb PLT entries parsing support
in ELF for llvm-objdump.

Implementation is similar to AArch64MCInstrAnalysis::findPltEntries. PLT
entry signatures are based on LLD code for PLT generation
(ARM::writePlt).

llvm-objdump tests are produced from lld/test/ELF/arm-plt-reloc.s,
lld/test/ELF/armv8-thumb-plt-reloc.s.
This commit is contained in:
Vladislav Dzhidzhoev 2025-03-26 20:18:23 +01:00 committed by GitHub
parent 9b7a7e4b9e
commit bcad050106
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 516 additions and 9 deletions

View File

@ -0,0 +1,2 @@
if "ARM" not in config.targets_to_build:
config.unsupported = True

View File

@ -0,0 +1,245 @@
// Test PLT section parsing on arm.
// REQUIRES: ld.lld
// RUN: %clang --target=armv6a-none-linux-gnueabi -fuse-ld=lld \
// RUN: -nostdlib -nostdinc -shared %s -o %t.v6a
// RUN: llvm-objdump --no-show-raw-insn --no-print-imm-hex \
// RUN: -d %t.v6a | FileCheck %s --check-prefixes=CHECK,LE
// Test PLT section parsing on armeb.
// RUN: %clang --target=armv6aeb-none-linux-gnueabi -fuse-ld=lld \
// RUN: -nostdlib -nostdinc -shared %s -o %t.v6aeb
// RUN: llvm-objdump --no-show-raw-insn --no-print-imm-hex \
// RUN: -d %t.v6aeb | FileCheck %s --check-prefixes=CHECK,BE
// RUN: obj2yaml %t.v6aeb | FileCheck %s --check-prefixes=NOBE8
// Test PLT section parsing on armeb with be8.
// RUN: %clang --target=armv7aeb-none-linux-gnueabi -fuse-ld=lld \
// RUN: -nostdlib -nostdinc -shared %s -o %t.v7aeb
// RUN: llvm-objdump --no-show-raw-insn --no-print-imm-hex \
// RUN: -d %t.v7aeb | FileCheck %s --check-prefixes=CHECK,BE
// RUN: obj2yaml %t.v7aeb | FileCheck %s --check-prefixes=BE8
// LE: file format elf32-littlearm
// BE: file format elf32-bigarm
// NOBE8-NOT: EF_ARM_BE8
// BE8: EF_ARM_BE8
// CHECK: Disassembly of section .text:
// CHECK-EMPTY:
// CHECK-NEXT: <_start>:
// CHECK-NEXT: push {r11, lr}
// CHECK-NEXT: mov r11, sp
// CHECK-NEXT: bl {{.*}} <func1@plt>
// CHECK-NEXT: bl {{.*}} <func2@plt>
// CHECK-NEXT: bl {{.*}} <func3@plt>
// CHECK: Disassembly of section .plt:
// CHECK: <func1@plt>:
// CHECK-NEXT: add r12, pc, #0, #12
// CHECK-NEXT: add r12, r12, #32, #20
// CHECK-NEXT: ldr pc, [r12, #132]!
// CHECK-NEXT: .word 0xd4d4d4d4
// CHECK-EMPTY:
// CHECK-NEXT: <func2@plt>:
// CHECK-NEXT: add r12, pc, #0, #12
// CHECK-NEXT: add r12, r12, #32, #20
// CHECK-NEXT: ldr pc, [r12, #120]!
// CHECK-NEXT: .word 0xd4d4d4d4
// CHECK-EMPTY:
// CHECK-NEXT: <func3@plt>:
// CHECK-NEXT: add r12, pc, #0, #12
// CHECK-NEXT: add r12, r12, #32, #20
// CHECK-NEXT: ldr pc, [r12, #108]!
// CHECK-NEXT: .word 0xd4d4d4d4
// Test PLT section parsing on thumb.
// RUN: %clang --target=thumbv8.1m.main-none-linux-eabi \
// RUN: -c %s -o %t.v8.o
// RUN: ld.lld --shared %t.v8.o -o %t.v8
// RUN: llvm-objdump --no-show-raw-insn --no-print-imm-hex \
// RUN: -d %t.v8 | FileCheck %s --check-prefixes=THUMB,LE
// Test PLT section parsing on thumbeb.
// RUN: %clang --target=thumbebv8.1m.main-none-linux-eabi \
// RUN: -c %s -o %t.v8eb.o
// RUN: ld.lld --shared %t.v8eb.o -o %t.v8eb
// RUN: llvm-objdump --no-show-raw-insn --no-print-imm-hex \
// RUN: -d %t.v8eb | FileCheck %s --check-prefixes=THUMB,BE
// RUN: obj2yaml %t.v8eb | FileCheck %s --check-prefixes=NOBE8
// Test PLT section parsing on thumbeb with be8.
// RUN: %clang --target=thumbebv8.1m.main-none-linux-eabi \
// RUN: -c %s -o %t.v8eb.be8.o
// RUN: ld.lld --shared --be8 %t.v8eb.be8.o -o %t.v8eb.be8
// RUN: llvm-objdump --no-show-raw-insn --no-print-imm-hex \
// RUN: -d %t.v8eb.be8 | FileCheck %s --check-prefixes=THUMB,BE
// RUN: obj2yaml %t.v8eb.be8 | FileCheck %s --check-prefixes=BE8
// THUMB: Disassembly of section .text:
// THUMB-EMPTY:
// THUMB-NEXT: <_start>:
// THUMB-NEXT: push {r7, lr}
// THUMB-NEXT: mov r7, sp
// THUMB-NEXT: bl {{.*}} <func1@plt>
// THUMB-NEXT: bl {{.*}} <func2@plt>
// THUMB-NEXT: bl {{.*}} <func3@plt>
// THUMB: Disassembly of section .plt:
// THUMB-EMPTY:
// THUMB: <func1@plt>:
// THUMB-NEXT: movw r12, #136
// THUMB-NEXT: movt r12, #2
// THUMB-NEXT: add r12, pc
// THUMB-NEXT: ldr.w pc, [r12]
// THUMB-NEXT: b 0x
// THUMB-EMPTY:
// THUMB-NEXT: <func2@plt>:
// THUMB-NEXT: movw r12, #124
// THUMB-NEXT: movt r12, #2
// THUMB-NEXT: add r12, pc
// THUMB-NEXT: ldr.w pc, [r12]
// THUMB-NEXT: b 0x
// THUMB-EMPTY:
// THUMB-NEXT: <func3@plt>:
// THUMB-NEXT: movw r12, #112
// THUMB-NEXT: movt r12, #2
// THUMB-NEXT: add r12, pc
// THUMB-NEXT: ldr.w pc, [r12]
// THUMB-NEXT: b 0x
// Test PLT section with long entries parsing on arm.
// RUN: echo "SECTIONS { \
// RUN: .text 0x1000 : { *(.text) } \
// RUN: .plt 0x2000 : { *(.plt) *(.plt.*) } \
// RUN: .got.plt 0x9000000 : { *(.got.plt) } \
// RUN: }" > %t.long.script
// RUN: %clang --target=armv6a-none-linux-gnueabi -fuse-ld=lld \
// RUN: -Xlinker --script=%t.long.script -nostdlib -nostdinc \
// RUN: -shared %s -o %t.v6a.long
// RUN: llvm-objdump --no-show-raw-insn --no-print-imm-hex \
// RUN: -d %t.v6a.long | FileCheck %s --check-prefixes=CHECKLONG,LE
// Test PLT section with long entries parsing on armeb.
// RUN: %clang --target=armv6aeb-none-linux-gnueabi -fuse-ld=lld \
// RUN: -Xlinker --script=%t.long.script -nostdlib -nostdinc \
// RUN: -shared %s -o %t.v6aeb.long
// RUN: llvm-objdump --no-show-raw-insn --no-print-imm-hex \
// RUN: -d %t.v6aeb.long | FileCheck %s --check-prefixes=CHECKLONG,BE
// RUN: obj2yaml %t.v6aeb.long | FileCheck %s --check-prefixes=NOBE8
// Test PLT section with long entries parsing on armeb with be8.
// RUN: %clang --target=armv7aeb-none-linux-gnueabi -fuse-ld=lld \
// RUN: -Xlinker --script=%t.long.script -nostdlib -nostdinc \
// RUN: -shared %s -o %t.v7aeb.long
// RUN: llvm-objdump --no-show-raw-insn --no-print-imm-hex \
// RUN: -d %t.v7aeb.long | FileCheck %s --check-prefixes=CHECKLONG,BE
// RUN: obj2yaml %t.v7aeb.long | FileCheck %s --check-prefixes=BE8
// CHECKLONG: Disassembly of section .text:
// CHECKLONG-EMPTY:
// CHECKLONG-NEXT: <_start>:
// CHECKLONG-NEXT: push {r11, lr}
// CHECKLONG-NEXT: mov r11, sp
// CHECKLONG-NEXT: bl 0x2020 <func1@plt>
// CHECKLONG-NEXT: bl 0x2030 <func2@plt>
// CHECKLONG-NEXT: bl 0x2040 <func3@plt>
// CHECKLONG: Disassembly of section .plt:
// CHECKLONG: 00002020 <func1@plt>:
// CHECKLONG-NEXT: ldr r12, [pc, #4]
// CHECKLONG-NEXT: add r12, r12, pc
// CHECKLONG-NEXT: ldr pc, [r12]
// CHECKLONG-NEXT: .word 0x08ffdfe0
// CHECKLONG-EMPTY:
// CHECKLONG-NEXT: 00002030 <func2@plt>:
// CHECKLONG-NEXT: ldr r12, [pc, #4]
// CHECKLONG-NEXT: add r12, r12, pc
// CHECKLONG-NEXT: ldr pc, [r12]
// CHECKLONG-NEXT: .word 0x08ffdfd4
// CHECKLONG-EMPTY:
// CHECKLONG-NEXT: 00002040 <func3@plt>:
// CHECKLONG-NEXT: ldr r12, [pc, #4]
// CHECKLONG-NEXT: add r12, r12, pc
// CHECKLONG-NEXT: ldr pc, [r12]
// CHECKLONG-NEXT: .word 0x08ffdfc8
// Test PLT section with mixed long and short entries parsing on arm.
// RUN: echo "SECTIONS { \
// RUN: .text 0x1000 : { *(.text) } \
// RUN: .plt 0x2000 : { *(.plt) *(.plt.*) } \
// RUN: .got.plt 0x8002020 : { *(.got.plt) } \
// RUN: }" > %t.mix.script
// RUN: %clang --target=armv6a-none-linux-gnueabi -fuse-ld=lld \
// RUN: -Xlinker --script=%t.mix.script -nostdlib -nostdinc \
// RUN: -shared %s -o %t.v6a.mix
// RUN: llvm-objdump --no-show-raw-insn --no-print-imm-hex \
// RUN: -d %t.v6a.mix | FileCheck %s --check-prefixes=CHECKMIX,LE
// Test PLT section with mixed long and short entries parsing on armeb.
// RUN: %clang --target=armv6aeb-none-linux-gnueabi -fuse-ld=lld \
// RUN: -Xlinker --script=%t.mix.script -nostdlib -nostdinc \
// RUN: -shared %s -o %t.v6aeb.mix
// RUN: llvm-objdump --no-show-raw-insn --no-print-imm-hex \
// RUN: -d %t.v6aeb.mix | FileCheck %s --check-prefixes=CHECKMIX,BE
// RUN: obj2yaml %t.v6aeb.mix | FileCheck %s --check-prefixes=NOBE8
// Test PLT section with mixed long and short entries parsing on armeb with be8.
// RUN: %clang --target=armv7aeb-none-linux-gnueabi -fuse-ld=lld \
// RUN: -Xlinker --script=%t.mix.script -nostdlib -nostdinc \
// RUN: -shared %s -o %t.v7aeb.mix
// RUN: llvm-objdump --no-show-raw-insn --no-print-imm-hex \
// RUN: -d %t.v7aeb.mix | FileCheck %s --check-prefixes=CHECKMIX,BE
// RUN: obj2yaml %t.v7aeb.mix | FileCheck %s --check-prefixes=BE8
// CHECKMIX: Disassembly of section .text:
// CHECKMIX-EMPTY:
// CHECKMIX-NEXT: <_start>:
// CHECKMIX-NEXT: push {r11, lr}
// CHECKMIX-NEXT: mov r11, sp
// CHECKMIX-NEXT: bl 0x2020 <func1@plt>
// CHECKMIX-NEXT: bl 0x2030 <func2@plt>
// CHECKMIX-NEXT: bl 0x2040 <func3@plt>
// CHECKMIX: Disassembly of section .plt:
// CHECKMIX: 00002020 <func1@plt>:
// CHECKMIX-NEXT: ldr r12, [pc, #4]
// CHECKMIX-NEXT: add r12, r12, pc
// CHECKMIX-NEXT: ldr pc, [r12]
// CHECKMIX-NEXT: .word 0x08000000
// CHECKMIX-EMPTY:
// CHECKMIX-NEXT: 00002030 <func2@plt>:
// CHECKMIX-NEXT: add r12, pc, #133169152
// CHECKMIX-NEXT: add r12, r12, #1044480
// CHECKMIX-NEXT: ldr pc, [r12, #4088]!
// CHECKMIX-NEXT: .word 0xd4d4d4d4
// CHECKMIX-EMPTY:
// CHECKMIX-NEXT: 00002040 <func3@plt>:
// CHECKMIX-NEXT: add r12, pc, #133169152
// CHECKMIX-NEXT: add r12, r12, #1044480
// CHECKMIX-NEXT: ldr pc, [r12, #4076]!
// CHECKMIX-NEXT: .word 0xd4d4d4d4
extern void *func1();
extern void *func2();
extern void *func3();
void _start() {
func1();
func2();
func3();
}

View File

@ -53,10 +53,14 @@
// DISASM-NEXT: 20214: d4 d4 d4 d4 .word 0xd4d4d4d4
// DISASM-NEXT: 20218: d4 d4 d4 d4 .word 0xd4d4d4d4
// DISASM-NEXT: 2021c: d4 d4 d4 d4 .word 0xd4d4d4d4
// DISASM-EMPTY:
// DISASM-NEXT: <bar2@plt>:
// DISASM-NEXT: 20220: add r12, pc, #0, #12
// DISASM-NEXT: 20224: add r12, r12, #32
// DISASM-NEXT: 20228: ldr pc, [r12, #212]!
// DISASM-NEXT: 2022c: d4 d4 d4 d4 .word 0xd4d4d4d4
// DISASM-EMPTY:
// DISASM-NEXT: <zed2@plt>:
// DISASM-NEXT: 20230: add r12, pc, #0, #12
// DISASM-NEXT: 20234: add r12, r12, #32
// DISASM-NEXT: 20238: ldr pc, [r12, #200]!

View File

@ -18,6 +18,8 @@
# CHECK-NEXT: d4 d4 d4 d4 .word 0xd4d4d4d4
# CHECK-NEXT: d4 d4 d4 d4 .word 0xd4d4d4d4
# CHECK-NEXT: d4 d4 d4 d4 .word 0xd4d4d4d4
# CHECK-EMPTY:
# CHECK-NEXT: <bar@plt>:
# CHECK-NEXT: e28fc600 add r12, pc, #0, #12
# CHECK-NEXT: e28cca20 add r12, r12, #32, #20
# CHECK-NEXT: e5bcf06c ldr pc, [r12, #0x6c]!

View File

@ -74,16 +74,22 @@ _start:
// DSO-NEXT: 10248: d4 d4 d4 d4 .word 0xd4d4d4d4
// DSO-NEXT: 1024c: d4 d4 d4 d4 .word 0xd4d4d4d4
// (0x10250 + 8) + (0 RoR 12) + (32 RoR 20 = 0x20000) + 140 = 0x302e4
// DSO-EMPTY:
// DSO-NEXT: <func1@plt>:
// DSO-NEXT: 10250: add r12, pc, #0, #12
// DSO-NEXT: 10254: add r12, r12, #32, #20
// DSO-NEXT: 10258: ldr pc, [r12, #140]!
// DSO-NEXT: 1025c: d4 d4 d4 d4 .word 0xd4d4d4d4
// (0x10260 + 8) + (0 RoR 12) + (32 RoR 20 = 0x20000) + 128 = 0x302e8
// DSO-EMPTY:
// DSO-NEXT: <func2@plt>:
// DSO-NEXT: 10260: add r12, pc, #0, #12
// DSO-NEXT: 10264: add r12, r12, #32, #20
// DSO-NEXT: 10268: ldr pc, [r12, #128]!
// DSO-NEXT: 1026c: d4 d4 d4 d4 .word 0xd4d4d4d4
// (0x10270 + 8) + (0 RoR 12) + (32 RoR 20 = 0x20000) + 116 = 0x302ec
// DSO-EMPTY:
// DSO-NEXT: <func3@plt>:
// DSO-NEXT: 10270: add r12, pc, #0, #12
// DSO-NEXT: 10274: add r12, r12, #32, #20
// DSO-NEXT: 10278: ldr pc, [r12, #116]!
@ -152,14 +158,20 @@ _start:
// CHECKHIGH-NEXT: 2014: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKHIGH-NEXT: 2018: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKHIGH-NEXT: 201c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKHIGH-EMPTY:
// CHECKHIGH-NEXT: <func1@plt>:
// CHECKHIGH-NEXT: 2020: add r12, pc, #16, #12
// CHECKHIGH-NEXT: 2024: add r12, r12, #1036288
// CHECKHIGH-NEXT: 2028: ldr pc, [r12, #4068]!
// CHECKHIGH-NEXT: 202c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKHIGH-EMPTY:
// CHECKHIGH-NEXT: <func2@plt>:
// CHECKHIGH-NEXT: 2030: add r12, pc, #16, #12
// CHECKHIGH-NEXT: 2034: add r12, r12, #1036288
// CHECKHIGH-NEXT: 2038: ldr pc, [r12, #4056]!
// CHECKHIGH-NEXT: 203c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKHIGH-EMPTY:
// CHECKHIGH-NEXT: <func3@plt>:
// CHECKHIGH-NEXT: 2040: add r12, pc, #16, #12
// CHECKHIGH-NEXT: 2044: add r12, r12, #1036288
// CHECKHIGH-NEXT: 2048: ldr pc, [r12, #4044]!
@ -220,14 +232,20 @@ _start:
// CHECKLONG-NEXT: 2014: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKLONG-NEXT: 2018: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKLONG-NEXT: 201c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKLONG-EMPTY:
// CHECKLONG-NEXT: <func1@plt>:
// CHECKLONG-NEXT: 2020: ldr r12, [pc, #4]
// CHECKLONG-NEXT: 2024: add r12, r12, pc
// CHECKLONG-NEXT: 2028: ldr pc, [r12]
// CHECKLONG-NEXT: 202c: e0 f0 10 11 .word 0x1110f0e0
// CHECKLONG-EMPTY:
// CHECKLONG-NEXT: <func2@plt>:
// CHECKLONG-NEXT: 2030: ldr r12, [pc, #4]
// CHECKLONG-NEXT: 2034: add r12, r12, pc
// CHECKLONG-NEXT: 2038: ldr pc, [r12]
// CHECKLONG-NEXT: 203c: d4 f0 10 11 .word 0x1110f0d4
// CHECKLONG-EMPTY:
// CHECKLONG-NEXT: <func3@plt>:
// CHECKLONG-NEXT: 2040: ldr r12, [pc, #4]
// CHECKLONG-NEXT: 2044: add r12, r12, pc
// CHECKLONG-NEXT: 2048: ldr pc, [r12]
@ -257,14 +275,20 @@ _start:
// CHECKLONG-EB-NEXT: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKLONG-EB-NEXT: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKLONG-EB-NEXT: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKLONG-EB-EMPTY:
// CHECKLONG-EB-NEXT: <func1@plt>:
// CHECKLONG-EB-NEXT: 2020: ldr r12, [pc, #4]
// CHECKLONG-EB-NEXT: add r12, r12, pc
// CHECKLONG-EB-NEXT: ldr pc, [r12]
// CHECKLONG-EB-NEXT: 11 10 f0 e0 .word 0x1110f0e0
// CHECKLONG-EB-EMPTY:
// CHECKLONG-EB-NEXT: <func2@plt>:
// CHECKLONG-EB-NEXT: 2030: ldr r12, [pc, #4]
// CHECKLONG-EB-NEXT: add r12, r12, pc
// CHECKLONG-EB-NEXT: ldr pc, [r12]
// CHECKLONG-EB-NEXT: 11 10 f0 d4 .word 0x1110f0d4
// CHECKLONG-EB-EMPTY:
// CHECKLONG-EB-NEXT: <func3@plt>:
// CHECKLONG-EB-NEXT: 2040: ldr r12, [pc, #4]
// CHECKLONG-EB-NEXT: add r12, r12, pc
// CHECKLONG-EB-NEXT: ldr pc, [r12]
@ -299,7 +323,7 @@ _start:
// RUN: llvm-objdump --no-print-imm-hex --triple=armv7aeb-none-linux-gnueabi -d --no-show-raw-insn %t6.be | FileCheck --check-prefix=CHECKMIX-EB %s
// RUN: llvm-readobj -S -r %t6.be | FileCheck --check-prefix=DSORELMIX %s
// RUN: ld.lld --be8 --hash-style=sysv --script %t3.script -shared %t1.be %t2.be -o %t6.be
// RUN: llvm-objdump --no-print-imm-hex --triple=armv7a-none-linux-gnueabi -d --no-show-raw-insn %t6.be | FileCheck --check-prefix=CHECKMIX-EB %s
// RUN: llvm-objdump --no-print-imm-hex --triple=armv7aeb-none-linux-gnueabi -d --no-show-raw-insn %t6.be | FileCheck --check-prefix=CHECKMIX-EB %s
// RUN: llvm-readobj -S -r %t6.be | FileCheck --check-prefix=DSORELMIX %s
// CHECKMIX: Disassembly of section .text:
@ -326,14 +350,20 @@ _start:
// CHECKMIX-NEXT: 2014: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKMIX-NEXT: 2018: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKMIX-NEXT: 201c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKMIX-EMPTY:
// CHECKMIX-NEXT: <func1@plt>:
// CHECKMIX-NEXT: 2020: ldr r12, [pc, #4]
// CHECKMIX-NEXT: 2024: add r12, r12, pc
// CHECKMIX-NEXT: 2028: ldr pc, [r12]
// CHECKMIX-NEXT: 202c: 00 00 00 08 .word 0x08000000
// CHECKMIX-EMPTY:
// CHECKMIX-NEXT: <func2@plt>:
// CHECKMIX-NEXT: 2030: add r12, pc, #133169152
// CHECKMIX-NEXT: 2034: add r12, r12, #1044480
// CHECKMIX-NEXT: 2038: ldr pc, [r12, #4088]!
// CHECKMIX-NEXT: 203c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKMIX-EMPTY:
// CHECKMIX-NEXT: <func3@plt>:
// CHECKMIX-NEXT: 2040: add r12, pc, #133169152
// CHECKMIX-NEXT: 2044: add r12, r12, #1044480
// CHECKMIX-NEXT: 2048: ldr pc, [r12, #4076]!
@ -363,14 +393,20 @@ _start:
// CHECKMIX-EB-NEXT: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKMIX-EB-NEXT: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKMIX-EB-NEXT: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKMIX-EB-EMPTY:
// CHECKMIX-EB-NEXT: <func1@plt>:
// CHECKMIX-EB-NEXT: 2020: ldr r12, [pc, #4]
// CHECKMIX-EB-NEXT: add r12, r12, pc
// CHECKMIX-EB-NEXT: ldr pc, [r12]
// CHECKMIX-EB-NEXT: 08 00 00 00 .word 0x08000000
// CHECKMIX-EB-EMPTY:
// CHECKMIX-EB-NEXT: <func2@plt>:
// CHECKMIX-EB-NEXT: 2030: add r12, pc, #133169152
// CHECKMIX-EB-NEXT: add r12, r12, #1044480
// CHECKMIX-EB-NEXT: ldr pc, [r12, #4088]!
// CHECKMIX-EB-NEXT: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECKMIX-EB-EMPTY:
// CHECKMIX-EB-NEXT: <func3@plt>:
// CHECKMIX-EB-NEXT: 2040: add r12, pc, #133169152
// CHECKMIX-EB-NEXT: add r12, r12, #1044480
// CHECKMIX-EB-NEXT: ldr pc, [r12, #4076]!

View File

@ -45,10 +45,14 @@ sym1:
// CHECK-NEXT: .word 0xd4d4d4d4
// CHECK-NEXT: .word 0xd4d4d4d4
// CHECK-NEXT: .word 0xd4d4d4d4
// CHECK-EMPTY:
// CHECK-NEXT: <elsewhere@plt>:
// CHECK-NEXT: 10230: add r12, pc, #0, #12
// CHECK-NEXT: add r12, r12, #32
// CHECK-NEXT: ldr pc, [r12, #124]!
// CHECK-NEXT: 1023c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK-EMPTY:
// CHECK-NEXT: <weakref@plt>:
// CHECK-NEXT: 10240: add r12, pc, #0, #12
// CHECK-NEXT: add r12, r12, #32
// CHECK-NEXT: ldr pc, [r12, #112]!

View File

@ -298,34 +298,50 @@ _start:
// CHECK-ARM-PLT-NEXT: 1624: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK-ARM-PLT-NEXT: 1628: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK-ARM-PLT-NEXT: 162c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK-ARM-PLT-EMPTY:
// CHECK-ARM-PLT-NEXT: <thumb_callee1@plt>
// CHECK-ARM-PLT-NEXT: 1630: add r12, pc, #0, #12
// CHECK-ARM-PLT-NEXT: 1634: add r12, r12, #0, #20
// CHECK-ARM-PLT-NEXT: 1638: ldr pc, [r12, #648]!
// CHECK-ARM-PLT-NEXT: 163c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK-ARM-PLT-EMPTY:
// CHECK-ARM-PLT-NEXT: <arm_callee1@plt>
// CHECK-ARM-PLT-NEXT: 1640: add r12, pc, #0, #12
// CHECK-ARM-PLT-NEXT: 1644: add r12, r12, #0, #20
// CHECK-ARM-PLT-NEXT: 1648: ldr pc, [r12, #636]!
// CHECK-ARM-PLT-NEXT: 164c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK-ARM-PLT-EMPTY:
// CHECK-ARM-PLT-NEXT: <arm_caller@plt>
// CHECK-ARM-PLT-NEXT: 1650: add r12, pc, #0, #12
// CHECK-ARM-PLT-NEXT: 1654: add r12, r12, #0, #20
// CHECK-ARM-PLT-NEXT: 1658: ldr pc, [r12, #624]!
// CHECK-ARM-PLT-NEXT: 165c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK-ARM-PLT-EMPTY:
// CHECK-ARM-PLT-NEXT: <thumb_callee2@plt>
// CHECK-ARM-PLT-NEXT: 1660: add r12, pc, #0, #12
// CHECK-ARM-PLT-NEXT: 1664: add r12, r12, #0, #20
// CHECK-ARM-PLT-NEXT: 1668: ldr pc, [r12, #612]!
// CHECK-ARM-PLT-NEXT: 166c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK-ARM-PLT-EMPTY:
// CHECK-ARM-PLT-NEXT: <thumb_callee3@plt>
// CHECK-ARM-PLT-NEXT: 1670: add r12, pc, #0, #12
// CHECK-ARM-PLT-NEXT: 1674: add r12, r12, #0, #20
// CHECK-ARM-PLT-NEXT: 1678: ldr pc, [r12, #600]!
// CHECK-ARM-PLT-NEXT: 167c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK-ARM-PLT-EMPTY:
// CHECK-ARM-PLT-NEXT: <arm_callee2@plt>
// CHECK-ARM-PLT-NEXT: 1680: add r12, pc, #0, #12
// CHECK-ARM-PLT-NEXT: 1684: add r12, r12, #0, #20
// CHECK-ARM-PLT-NEXT: 1688: ldr pc, [r12, #588]!
// CHECK-ARM-PLT-NEXT: 168c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK-ARM-PLT-EMPTY:
// CHECK-ARM-PLT-NEXT: <arm_callee3@plt>
// CHECK-ARM-PLT-NEXT: 1690: add r12, pc, #0, #12
// CHECK-ARM-PLT-NEXT: 1694: add r12, r12, #0, #20
// CHECK-ARM-PLT-NEXT: 1698: ldr pc, [r12, #576]!
// CHECK-ARM-PLT-NEXT: 169c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK-ARM-PLT-EMPTY:
// CHECK-ARM-PLT-NEXT: <thumb_caller@plt>
// CHECK-ARM-PLT-NEXT: 16a0: add r12, pc, #0, #12
// CHECK-ARM-PLT-NEXT: 16a4: add r12, r12, #0, #20
// CHECK-ARM-PLT-NEXT: 16a8: ldr pc, [r12, #564]!

View File

@ -96,14 +96,20 @@ far_nonpreemptible_alias:
// CHECK4-NEXT: 4000024: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK4-NEXT: 4000028: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK4-NEXT: 400002c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK4-EMPTY:
// CHECK4-NEXT: <elsewhere@plt>:
// CHECK4-NEXT: 4000030: e28fc600 add r12, pc, #0, #12
// CHECK4-NEXT: 4000034: e28cca20 add r12, r12, #32
// CHECK4-NEXT: 4000038: e5bcf08c ldr pc, [r12, #140]!
// CHECK4-NEXT: 400003c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK4-EMPTY:
// CHECK4-NEXT: <preemptible@plt>:
// CHECK4-NEXT: 4000040: e28fc600 add r12, pc, #0, #12
// CHECK4-NEXT: 4000044: e28cca20 add r12, r12, #32
// CHECK4-NEXT: 4000048: e5bcf080 ldr pc, [r12, #128]!
// CHECK4-NEXT: 400004c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK4-EMPTY:
// CHECK4-NEXT: <far_preemptible@plt>:
// CHECK4-NEXT: 4000050: e28fc600 add r12, pc, #0, #12
// CHECK4-NEXT: 4000054: e28cca20 add r12, r12, #32
// CHECK4-NEXT: 4000058: e5bcf074 ldr pc, [r12, #116]!

View File

@ -83,16 +83,22 @@ _start:
// DSO-NEXT: 10248: d4 d4 d4 d4 .word 0xd4d4d4d4
// DSO-NEXT: 1024c: d4 d4 d4 d4 .word 0xd4d4d4d4
// (0x10250 + 8) + (0 RoR 12) + (32 RoR 20 = 0x20000) + 140 = 0x302e4
// DSO-EMPTY:
// DSO-NEXT: <func1@plt>:
// DSO-NEXT: 10250: e28fc600 add r12, pc, #0, #12
// DSO-NEXT: 10254: e28cca20 add r12, r12, #32, #20
// DSO-NEXT: 10258: e5bcf08c ldr pc, [r12, #140]!
// DSO-NEXT: 1025c: d4 d4 d4 d4 .word 0xd4d4d4d4
// (0x10260 + 8) + (0 RoR 12) + (32 RoR 20 = 0x20000) + 128 = 0x302e8
// DSO-EMPTY:
// DSO-NEXT: <func2@plt>:
// DSO-NEXT: 10260: e28fc600 add r12, pc, #0, #12
// DSO-NEXT: 10264: e28cca20 add r12, r12, #32, #20
// DSO-NEXT: 10268: e5bcf080 ldr pc, [r12, #128]!
// DSO-NEXT: 1026c: d4 d4 d4 d4 .word 0xd4d4d4d4
// (0x10270 + 8) + (0 RoR 12) + (32 RoR 20 = 0x20000) + 116 = 0x302ec
// DSO-EMPTY:
// DSO-NEXT: <func3@plt>:
// DSO-NEXT: 10270: e28fc600 add r12, pc, #0, #12
// DSO-NEXT: 10274: e28cca20 add r12, r12, #32, #20
// DSO-NEXT: 10278: e5bcf074 ldr pc, [r12, #116]!

View File

@ -86,10 +86,14 @@ preemptible2:
// CHECK-PLT-NEXT: d00034: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK-PLT-NEXT: d00038: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK-PLT-NEXT: d0003c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK-PLT-EMPTY:
// CHECK-PLT-NEXT: <preemptible@plt>:
// CHECK-PLT-NEXT: d00040: add r12, pc, #0, #12
// CHECK-PLT-NEXT: d00044: add r12, r12, #32, #20
// CHECK-PLT-NEXT: d00048: ldr pc, [r12, #124]!
// CHECK-PLT-NEXT: d0004c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK-PLT-EMPTY:
// CHECK-PLT-NEXT: <preemptible2@plt>:
// CHECK-PLT-NEXT: d00050: add r12, pc, #0, #12
// CHECK-PLT-NEXT: d00054: add r12, r12, #32, #20
// CHECK-PLT-NEXT: d00058: ldr pc, [r12, #112]!

View File

@ -109,10 +109,14 @@ callers:
// CHECK3-NEXT: 1100034: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK3-NEXT: 1100038: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK3-NEXT: 110003c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK3-EMPTY:
// CHECK3-NEXT: <imported@plt>:
// CHECK3-NEXT: 1100040: e28fc600 add r12, pc, #0, #12
// CHECK3-NEXT: 1100044: e28cca20 add r12, r12, #32
// CHECK3-NEXT: 1100048: e5bcf07c ldr pc, [r12, #124]!
// CHECK3-NEXT: 110004c: d4 d4 d4 d4 .word 0xd4d4d4d4
// CHECK3-EMPTY:
// CHECK3-NEXT: <imported2@plt>:
// CHECK3-NEXT: 1100050: e28fc600 add r12, pc, #0, #12
// CHECK3-NEXT: 1100054: e28cca20 add r12, r12, #32
// CHECK3-NEXT: 1100058: e5bcf070 ldr pc, [r12, #112]!

View File

@ -101,18 +101,24 @@ _start:
// DSO-NEXT: .word 0xd4d4d4d4
/// 136 + 2 << 16 + 0x1026c = 0x302f4 = got entry 1
// DSO-EMPTY:
// DSO-NEXT: <func1@plt>:
// DSO-NEXT: 10260: f240 0c88 movw r12, #136
// DSO-NEXT: f2c0 0c02 movt r12, #2
// DSO-NEXT: 44fc add r12, pc
// DSO-NEXT: f8dc f000 ldr.w pc, [r12]
// DSO-NEXT: e7fc b 0x1026a
/// 124 + 2 << 16 + 0x1027c = 0x302f8 = got entry 2
// DSO-EMPTY:
// DSO-NEXT: <func2@plt>:
// DSO-NEXT: 10270: f240 0c7c movw r12, #124
// DSO-NEXT: f2c0 0c02 movt r12, #2
// DSO-NEXT: 44fc add r12, pc
// DSO-NEXT: f8dc f000 ldr.w pc, [r12]
// DSO-NEXT: e7fc b 0x1027a
/// 112 + 2 << 16 + 0x1028c = 0x302fc = got entry 3
// DSO-EMPTY:
// DSO-NEXT: <func3@plt>:
// DSO-NEXT: 10280: f240 0c70 movw r12, #112
// DSO-NEXT: f2c0 0c02 movt r12, #2
// DSO-NEXT: 44fc add r12, pc

View File

@ -799,6 +799,12 @@ ELFObjectFileBase::getPltEntries(const MCSubtargetInfo &STI) const {
case Triple::aarch64_be:
JumpSlotReloc = ELF::R_AARCH64_JUMP_SLOT;
break;
case Triple::arm:
case Triple::armeb:
case Triple::thumb:
case Triple::thumbeb:
JumpSlotReloc = ELF::R_ARM_JUMP_SLOT;
break;
case Triple::hexagon:
JumpSlotReloc = ELF::R_HEX_JMP_SLOT;
GlobDatReloc = ELF::R_HEX_GLOB_DAT;

View File

@ -431,6 +431,10 @@ public:
std::optional<uint64_t>
evaluateMemoryOperandAddress(const MCInst &Inst, const MCSubtargetInfo *STI,
uint64_t Addr, uint64_t Size) const override;
std::vector<std::pair<uint64_t, uint64_t>>
findPltEntries(uint64_t PltSectionVA, ArrayRef<uint8_t> PltContents,
const MCSubtargetInfo &STI) const override;
};
} // namespace
@ -621,6 +625,138 @@ std::optional<uint64_t> ARMMCInstrAnalysis::evaluateMemoryOperandAddress(
}
}
template <typename T, size_t N>
static bool instructionsMatch(const T (&Insns)[N], const uint8_t *Buf,
llvm::endianness E) {
for (size_t I = 0; I < N; ++I) {
T Val = support::endian::read<T>(Buf + I * sizeof(T), E);
if (Val != Insns[I])
return false;
}
return true;
}
std::vector<std::pair<uint64_t, uint64_t>>
ARMMCInstrAnalysis::findPltEntries(uint64_t PltSectionVA,
ArrayRef<uint8_t> PltContents,
const MCSubtargetInfo &STI) const {
llvm::endianness DataEndianness = STI.getTargetTriple().isLittleEndian()
? endianness::little
: endianness::big;
llvm::endianness InstrEndianness =
STI.checkFeatures("+big-endian-instructions") ? endianness::big
: endianness::little;
// Do a lightweight parsing of PLT entries.
std::vector<std::pair<uint64_t, uint64_t>> Result;
if (STI.checkFeatures("+thumb-mode")) {
for (uint64_t Byte = 0, End = PltContents.size(); Byte + 12 < End;
Byte += 16) {
// Expected instruction sequence:
//
// movw ip, #lower16
// movt ip, #upper16
// add ip, pc
// ldr.w pc, [ip]
// b . -4
uint32_t MovwPart1 =
support::endian::read16(PltContents.data() + Byte, InstrEndianness);
if ((MovwPart1 & 0xffb0) != 0xf200)
continue;
uint32_t MovwPart2 = support::endian::read16(
PltContents.data() + Byte + 2, InstrEndianness);
if ((MovwPart2 & 0x8f00) != 0xc00)
continue;
uint64_t OffsetLower = (MovwPart2 & 0xff) + ((MovwPart2 & 0x7000) >> 4) +
((MovwPart1 & 0x400) << 1) +
((MovwPart1 & 0xf) << 12);
uint32_t MovtPart1 = support::endian::read16(
PltContents.data() + Byte + 4, InstrEndianness);
if ((MovtPart1 & 0xfbf0) != 0xf2c0)
continue;
uint32_t MovtPart2 = support::endian::read16(
PltContents.data() + Byte + 6, InstrEndianness);
if ((MovtPart2 & 0x8f00) != 0xc00)
continue;
uint64_t OffsetHigher =
((MovtPart2 & 0xff) << 16) + ((MovtPart2 & 0x7000) << 12) +
((MovtPart1 & 0x400) << 17) + ((MovtPart1 & 0xf) << 28);
const uint16_t Insns[] = {
0x44fc, // add ip, pc
0xf8dc, 0xf000, // ldr.w pc, [ip]
0xe7fc, // b . -4
};
if (!instructionsMatch(Insns, PltContents.data() + Byte + 8,
InstrEndianness))
continue;
// add ip, pc at Byte + 8 + thumb-pc-bias = 12
uint64_t Offset = (PltSectionVA + Byte + 12) + OffsetLower + OffsetHigher;
Result.emplace_back(PltSectionVA + Byte, Offset);
}
} else {
const uint32_t LongEntryInsns[] = {
0xe59fc004, // ldr ip, L2
0xe08cc00f, // L1: add ip, ip, pc
0xe59cf000, // ldr pc, [ip]
};
for (uint64_t Byte = 0, End = PltContents.size(); Byte + 12 < End;
Byte += 4) {
// Is it a long entry?
if (instructionsMatch(LongEntryInsns, PltContents.data() + Byte,
InstrEndianness)) {
// Expected instruction sequence:
//
// ldr ip, L2
// L1: add ip, ip, pc
// ldr pc, [ip]
// L2: .word Offset(&(.got.plt) - L1 - 8
uint64_t Offset = (PltSectionVA + Byte + 12) +
support::endian::read32(
PltContents.data() + Byte + 12, DataEndianness);
Result.emplace_back(PltSectionVA + Byte, Offset);
Byte += 12;
} else {
// Expected instruction sequence:
//
// L1: add ip, pc, #0x0NN00000 Offset(&(.got.plt) - L1 - 8
// add ip, ip, #0x000NN000 Offset(&(.got.plt) - L1 - 8
// ldr pc, [ip, #0x00000NNN] Offset(&(.got.plt) - L1 - 8
uint32_t Add1 =
support::endian::read32(PltContents.data() + Byte, InstrEndianness);
if ((Add1 & 0xe28fc600) != 0xe28fc600)
continue;
uint32_t Add2 = support::endian::read32(PltContents.data() + Byte + 4,
InstrEndianness);
if ((Add2 & 0xe28cca00) != 0xe28cca00)
continue;
uint32_t Ldr = support::endian::read32(PltContents.data() + Byte + 8,
InstrEndianness);
if ((Ldr & 0xe5bcf000) != 0xe5bcf000)
continue;
// add ip, pc, #offset at Byte + 0 + arm-pc-bias = 8
uint64_t Offset = (PltSectionVA + Byte + 8) + ((Add1 & 0xff) << 20) +
((Add2 & 0xff) << 12) + (Ldr & 0xfff);
Result.emplace_back(PltSectionVA + Byte, Offset);
Byte += 8;
}
}
}
return Result;
}
static MCInstrAnalysis *createARMMCInstrAnalysis(const MCInstrInfo *Info) {
return new ARMMCInstrAnalysis(Info);
}

View File

@ -1233,12 +1233,7 @@ addMissingWasmCodeSymbols(const WasmObjectFile &Obj,
}
}
static void addPltEntries(const MCSubtargetInfo &STI, const ObjectFile &Obj,
std::map<SectionRef, SectionSymbolsTy> &AllSymbols,
StringSaver &Saver) {
auto *ElfObj = dyn_cast<ELFObjectFileBase>(&Obj);
if (!ElfObj)
return;
static DenseMap<StringRef, SectionRef> getSectionNames(const ObjectFile &Obj) {
DenseMap<StringRef, SectionRef> Sections;
for (SectionRef Section : Obj.sections()) {
Expected<StringRef> SecNameOrErr = Section.getName();
@ -1248,13 +1243,23 @@ static void addPltEntries(const MCSubtargetInfo &STI, const ObjectFile &Obj,
}
Sections[*SecNameOrErr] = Section;
}
return Sections;
}
static void addPltEntries(const MCSubtargetInfo &STI, const ObjectFile &Obj,
DenseMap<StringRef, SectionRef> &SectionNames,
std::map<SectionRef, SectionSymbolsTy> &AllSymbols,
StringSaver &Saver) {
auto *ElfObj = dyn_cast<ELFObjectFileBase>(&Obj);
if (!ElfObj)
return;
for (auto Plt : ElfObj->getPltEntries(STI)) {
if (Plt.Symbol) {
SymbolRef Symbol(*Plt.Symbol, ElfObj);
uint8_t SymbolType = getElfSymbolType(Obj, Symbol);
if (Expected<StringRef> NameOrErr = Symbol.getName()) {
if (!NameOrErr->empty())
AllSymbols[Sections[Plt.Section]].emplace_back(
AllSymbols[SectionNames[Plt.Section]].emplace_back(
Plt.Address, Saver.save((*NameOrErr + "@plt").str()), SymbolType);
continue;
} else {
@ -1770,9 +1775,34 @@ disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj,
if (Obj.isELF() && Obj.sections().empty())
createFakeELFSections(Obj);
DisassemblerTarget *PltTarget = DT;
auto SectionNames = getSectionNames(Obj);
if (SecondaryTarget && isArmElf(Obj)) {
auto PltSectionRef = SectionNames.find(".plt");
if (PltSectionRef != SectionNames.end()) {
bool PltIsThumb = false;
for (auto [Addr, SymbolName] : AllMappingSymbols[PltSectionRef->second]) {
if (Addr != 0)
continue;
if (SymbolName == 't') {
PltIsThumb = true;
break;
}
if (SymbolName == 'a')
break;
}
if (PrimaryTarget.SubtargetInfo->checkFeatures("+thumb-mode"))
PltTarget = PltIsThumb ? &PrimaryTarget : &*SecondaryTarget;
else
PltTarget = PltIsThumb ? &*SecondaryTarget : &PrimaryTarget;
}
}
BumpPtrAllocator A;
StringSaver Saver(A);
addPltEntries(*DT->SubtargetInfo, Obj, AllSymbols, Saver);
addPltEntries(*PltTarget->SubtargetInfo, Obj, SectionNames, AllSymbols,
Saver);
// Create a mapping from virtual address to section. An empty section can
// cause more than one section at the same address. Sort such sections to be