Como posso pular em relação ao PC usando o assembler GNU para AVR?
-
21-09-2019 - |
Pergunta
Eu tenho um arquivo binário que desmontei usando o AVR-OBJCOPY. A tabela de vetores de interrupção parece:
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)
Quero remontar esse arquivo com algumas modificações. Eu o reformatei removendo as duas primeiras colunas para que seja um arquivo de montagem regular. ou seja:
.org 0 rjmp .+38 ; 0x28, RESET rjmp .+880 ; 0x374, INT0 (snip)
No entanto, quando eu corro
$ avr-as -mmcu=atmega8 test.asm
e depois desmonte o arquivo gerado. (Usando objcopy -s A.out) A saída se parece:
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 ; 0x22 22: 00 c0 rjmp .+0 ; 0x24 24: 00 c0 rjmp .+0 ; 0x26 26: 00 00 nop 28: f8 94 cli (snip)
Então, como posso fazer com que o AVR-como respeite os saltos relativos para PC?
Solução
Eu encontrei a resposta!
Eu estava montando, mas não vinculando. Portanto, o assembler estava preenchendo todos os saltos/chamadas/ramificações relativas com.+0.
Para corrigir isso, eu precisava criar um script de ligação personalizado que eu chamei de linker.x que contém o seguinte:
SECTIONS { . = 0x0; .text : { *(.text) } }
Isso diz ao vinculador para iniciar a seção .text no endereço 0.
Então eu poderia vincular o código usando:
$ avr-ld -mavr4 -Tlinker.x a.out -o output.o
Depois de vincular usando o comando acima, todos os.+0's foram preenchidos com seus valores corretos!
A razão para isso é porque até o estágio de vinculação, AS/GCC não sabe o que mais será incluído no arquivo binário. É o vinculador que leva todos os arquivos de objeto individual e os combina em um. Portanto, se o estágio do vinculador nunca for executado, não há como preencher os saltos relativos com saltos absolutos.
O assembler da AVR faz a montagem e a ligação. Mas o assembler GNU é mais genérico e você precisa vincular separadamente.
Outras dicas
Estou assumindo isso rjmp PC+2
não funciona no AVR-AS? É assim que eu faria no AVR Studio ...