-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[lld][ELF][AVR] Add range check for R_AVR_13_PCREL #67636
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-lld @llvm/pr-subscribers-lld-elf ChangesSome large AVR programs (for devices without long jump) may exceed 128KiB, and lld should give explicit errors other than generate wrong executables silently. Full diff: https://github.com/llvm/llvm-project/pull/67636.diff 2 Files Affected:
diff --git a/lld/ELF/Arch/AVR.cpp b/lld/ELF/Arch/AVR.cpp
index 4905d61796fa98f..d5cba4c70e8564b 100644
--- a/lld/ELF/Arch/AVR.cpp
+++ b/lld/ELF/Arch/AVR.cpp
@@ -238,6 +238,7 @@ void AVR::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
break;
}
case R_AVR_13_PCREL: {
+ checkInt(loc, val, 13, rel);
checkAlignment(loc, val, 2, rel);
const uint16_t target = (val - 2) >> 1;
write16le(loc, (read16le(loc) & 0xf000) | (target & 0xfff));
diff --git a/lld/test/ELF/avr-errors.s b/lld/test/ELF/avr-errors.s
new file mode 100644
index 000000000000000..bbf88f887a4466b
--- /dev/null
+++ b/lld/test/ELF/avr-errors.s
@@ -0,0 +1,27 @@
+; REQUIRES: avr
+; RUN: llvm-mc -filetype=obj -triple=avr -mcpu=atmega328 %s -o %t.o
+; RUN: not ld.lld %t.o -o %t 2>&1 -Ttext=0x1000 --defsym=callee0=0xf00 --defsym=callee1=0x2048 --defsym=callee2=0x100f | FileCheck %s
+
+.section .LDI,"ax",@progbits
+
+.globl __init
+__init:
+
+; CHECK: relocation R_AVR_7_PCREL out of range: {{.*}} 'callee0'
+; CHECK-NOT: R_AVR_13_PCREL {{.*}} 'callee0'
+; CHECK-NOT: R_AVR_CALL {{.*}} 'callee0'
+brne callee0
+rjmp callee0
+jmp callee0
+
+; CHECK: relocation R_AVR_7_PCREL out of range: {{.*}} 'callee1'
+; CHECK: relocation R_AVR_13_PCREL out of range: {{.*}} 'callee1'
+; CHECK-NOT: R_AVR_CALL {{.*}} 'callee1'
+breq callee1
+rcall callee1
+call callee1
+
+; CHECK: improper alignment for relocation R_AVR_7_PCREL: {{.*}} not aligned to 2 bytes
+; CHECK: improper alignment for relocation R_AVR_13_PCREL: {{.*}} not aligned to 2 bytes
+brlt callee2
+rcall callee2
|
Here is a real world program that gnu-ld reports an error, but lld silently generate an incorrect executable: |
lld should report explicit range and alignment errors for some relocations other than silently generate incorrect ELF outputs.
The change to
When I undo that one line change using the following patch, all AVR tests pass: case R_AVR_7_PCREL: {
- checkInt(loc, val - 2, 7, rel);
+ checkInt(loc, val, 7, rel);
checkAlignment(loc, val, 2, rel);
const uint16_t target = (val - 2) >> 1;
write16le(loc, (read16le(loc) & 0xfc07) | ((target & 0x7f) << 3));
break;
} |
A correct fix is the following: --- a/lld/ELF/Arch/AVR.cpp
+++ b/lld/ELF/Arch/AVR.cpp
@@ -231,7 +231,7 @@ void AVR::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
// Since every jump destination is word aligned we gain an extra bit
case R_AVR_7_PCREL: {
- checkInt(loc, val - 2, 7, rel);
+ checkInt(loc, val - 2, 8, rel);
checkAlignment(loc, val, 2, rel);
const uint16_t target = (val - 2) >> 1;
write16le(loc, (read16le(loc) & 0xfc07) | ((target & 0x7f) << 3)); I've verified the behavior against avr-ld. |
Some large AVR programs (for devices without long jump) may exceed 128KiB, and lld should give explicit errors other than generate wrong executables silently.