How can I jump relative to the PC using the gnu assembler for AVR?
I have a binary file that I've disassembled using avr-objcopy. The interrupt vector table looks like:
00000000 : ; VECTOR TABLE 0: 13 c0 rjmp .+38 ; 0x28, RESET 2: b8 c1 rjmp .+880 ; 0x374, INT0 4: fd cf rjmp .-6 ; 0x0 6: fc cf rjmp .-8 ; 0x0 8: fb cf rjmp .-10 ; 0x0 a: fa cf rjmp .-12 ; 0x0 c: f9 cf rjmp .-14 ; 0x0 e: f8 cf rjmp .-16 ; 0x0 10: f7 cf rjmp .-18 ; 0x0 12: c7 c1 rjmp .+910 ; 0x3a2, TIMER1 OVF 14: f5 cf rjmp .-22 ; 0x0 16: f4 cf rjmp .-24 ; 0x0 18: f3 cf rjmp .-26 ; 0x0 1a: f2 cf rjmp .-28 ; 0x0 1c: 2b c2 rjmp .+1110 ; 0x474, ADC conversion complete 1e: f0 cf rjmp .-32 ; 0x0 20: ef cf rjmp .-34 ; 0x0 22: ee cf rjmp .-36 ; 0x0 24: ed cf rjmp .-38 ; 0x0 26: 00 00 nop ; START 28: f8 94 cli (snip)
I want to reassemble this file with a few modifications. I've reformatted it by removing the first 2 columns so that it is a regular assembly file. ie:
.org 0 rjmp .+38 ; 0x28, RESET rjmp .+880 ; 0x374, INT0 (snip)
However, when I run
$ avr-as -mmcu=atmega8 test.asm
and then disassemble the generated file. (using objcopy -S a.out) The output looks like:
00000000 : 0: 00 c0 rjmp .+0 ; 0x2 2: 00 c0 rjmp .+0 ; 0x4 4: 00 c0 rjmp .+0 ; 0x6 6: 00 c0 rjmp .+0 ; 0x8 8: 00 c0 rjmp .+0 ; 0xa a: 00 c0 rjmp .+0 ; 0xc c: 00 c0 rjmp .+0 ; 0xe e: 00 c0 rjmp .+0 ; 0x10 10: 00 c0 rjmp .+0 ; 0x12 12: 00 c0 rjmp .+0 ; 0x14 14: 00 c0 rjmp .+0 ; 0x16 16: 00 c0 rjmp .+0 ; 0x18 18: 00 c0 rjmp .+0 ; 0x1a 1a: 00 c0 rjmp .+0 ; 0x1c 1c: 00 c0 rjmp .+0 ; 0x1e 1e: 00 c0 rjmp .+0 ; 0x20 20: 00 c0 rjmp .+0 开发者_如何学C ; 0x22 22: 00 c0 rjmp .+0 ; 0x24 24: 00 c0 rjmp .+0 ; 0x26 26: 00 00 nop 28: f8 94 cli (snip)
So how can I get avr-as to respect the PC-relative jumps?
I found the answer!
I was assembling but not linking. So the assembler was filling in all relative jumps/calls/branches with .+0.
To fix this I needed to create a custom linker script I called linker.x which contains the following:
SECTIONS { . = 0x0; .text : { *(.text) } }
This tells the linker to start the .text section at address 0.
Then I could link the code using:
$ avr-ld -mavr4 -Tlinker.x a.out -o output.o
After linking using the above command all of the .+0's were filled in with their correct values!
The reason for this, is because until the linking stage, as/gcc don't know what else is going to be included in the binary file. It is the linker that takes all the individual object files and combines them into one. So if the linker stage is never run, there is no way to fill in the relative jumps with absolute jumps.
AVR's assembler does the both assembling and linking. But the gnu assembler is more generic and so you need to link separately.
I'm assuming that rjmp PC+2
doesnt work in avr-as ? That's how I'd do it in AVR Studio...
精彩评论