llvm-project
llvm-project copied to clipboard
Unexpected assembly output using relative offsets in inline assembler
Bugzilla Link | 47749 |
Version | 10.0 |
OS | Linux |
Attachments | Example Program showing the unexpected behaviour |
Extended Description
While porting C source (https://github.com/cpldcpu/light_ws2812/blob/master/light_ws2812_AVR/Light_WS2812/light_ws2812.c) to Zig, which uses LLVM as a backend, I noticed that the "rjmp .+0" instructions that are used as 2-cycle NOPs under avr-gcc assembled to "rjmp .-2" (infinite loops) under Zig and LLVM/Clang.
Here is some code to reproduce:
/*
$ clang -target avr-freestanding-eabi -mmcu=atmega32u2 demo_c.c -c -o demo_c.o
$ avr-gcc -mmcu=atmega32u2 demo_c.o -o demo_c.elf
$ avr-objdump --siassemble=main demo_c.elf
demo_c.elf: file format elf32-avr
Disassembly of section .text:
00000000 <main>:
0: fe cf rjmp .-4 ; 0xfffffffe <__eeprom_end+0xff7efffe>
2: ff cf rjmp .-2 ; 0x2 <main+0x2>
4: 00 c0 rjmp .+0 ; 0x6 <main+0x6>
6: 80 e0 ldi r24, 0x00 ; 0
8: 90 e0 ldi r25, 0x00 ; 0
a: 08 95 ret
*/
int main() {
asm("rjmp .-2");
asm("rjmp .+0");
asm("rjmp .+2");
}
(this file is also attached as demo_c.c)
Note that just inspecting the object file created using clang will confusingly show "rjmp .+0" thrice since the actual offset is set using relocation fixups at that stage.
rjmp
seems can not be decoded correctly, for the following assembly program avr5.S
,
.text
.globl main
.p2align 1
main:
ldi r24, lo8(def) ; Load lower byte of variable def 16-bit address to r24
ldi r25, hi8(def) ; Load higher byte of variable def 16-bit address to r25
rjmp main
.section .data
.type abc, @object
.type def, @object
.globl abc
.globl def
abc:
.short 100
def:
.short 200
Build it with command clang avr5.S --target=avr -mmcu=atmega328 -o avr5.out
.
avr-objdump
can correctly decode the generated avr5.out
0000007c <main>:
7c: 82 e0 ldi r24, 0x02 ; 2
7e: 91 e0 ldi r25, 0x01 ; 1
80: fd cf rjmp .-6 ; 0x7c <main>
But llvm-objdump -d avr5.out --mcpu=atmega328
can not decode the rjmp
instruction correctly.
0000007c <main>:
7c: 82 e0 ldi r24, 2
7e: 91 e0 ldi r25, 1
80: fd cf rjmp <unknown>
This bug affects some tests : https://github.com/llvm/llvm-project/blob/main/lld/test/ELF/avr-reloc.s#L64
fixed by https://reviews.llvm.org/D140815 https://reviews.llvm.org/D140816
The above patches fix the bug that the llvm-objdump can not correctly decode RJMP/RCALL and the relative branch instructions.
However clang still emits wrong addend field in the .rela.text of AVR relocatable ELF files, which leads to the original bug reported by @s-ol . I guess the bug may be inside the AVR MC layer.
In #59962 I have an example which has nothing to do with clang, it shows that llvm-mc
generates object file output which doesn't match llc
's output for the same input.
duplicate to https://github.com/llvm/llvm-project/issues/60019 .
Input:
.text
.globl main
main:
rjmp .-6
llvm-mc
output, linked with avr-gcc
:
$ llvm-mc --arch=avr --mcpu=atmega32u4 -filetype=obj blah.s -o blah.s.o
$ avr-gcc -mmcu=atmega32u4 blah.s.o -o blah.s.o.elf
$ avr-objdump -d -r blah.s.o.elf
...
000000c4 <main>:
c4: fc cf rjmp .-8 ; 0xbe <__ctors_end+0x12>