开发者

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...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜