llvm-project icon indicating copy to clipboard operation
llvm-project copied to clipboard

Unexpected assembly output using relative offsets in inline assembler

Open s-ol opened this issue 4 years ago • 1 comments

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.

s-ol avatar Oct 06 '20 21:10 s-ol

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>

benshi001 avatar May 16 '22 00:05 benshi001

This bug affects some tests : https://github.com/llvm/llvm-project/blob/main/lld/test/ELF/avr-reloc.s#L64

benshi001 avatar Jan 01 '23 02:01 benshi001

fixed by https://reviews.llvm.org/D140815 https://reviews.llvm.org/D140816

benshi001 avatar Jan 01 '23 08:01 benshi001

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.

benshi001 avatar Jan 01 '23 11:01 benshi001

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.

gergoerdi avatar Jan 13 '23 16:01 gergoerdi

duplicate to https://github.com/llvm/llvm-project/issues/60019 .

benshi001 avatar Jan 14 '23 06:01 benshi001

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>

gergoerdi avatar Jan 14 '23 08:01 gergoerdi