Gcc 如何在AVR libc中访问PC指针(使用汇编)?
我正在尝试使用AVRCC在AVR汇编中编写一些条件跳转。根据AVR指令集手册,Gcc 如何在AVR libc中访问PC指针(使用汇编)?,gcc,assembly,linker,branch,avr,Gcc,Assembly,Linker,Branch,Avr,我正在尝试使用AVRCC在AVR汇编中编写一些条件跳转。根据AVR指令集手册,brxx指令接收一个操作数k,并跳到PC+k+1。另外,根据PDF中的教程,我应该能够使用PC操作数进行如下跳转: brne PC+2 但是,当我编写这样的测试代码时: #include <avr/io.h> .section .text .global main ; Note [5] main: sbi _SFR_IO_ADDR(DDRA), PA0 sbi _SFR_IO_ADDR(P
brxx
指令接收一个操作数k
,并跳到PC+k+1
。另外,根据PDF中的教程,我应该能够使用PC
操作数进行如下跳转:
brne PC+2
但是,当我编写这样的测试代码时:
#include <avr/io.h>
.section .text
.global main ; Note [5]
main:
sbi _SFR_IO_ADDR(DDRA), PA0
sbi _SFR_IO_ADDR(PORTA), PA0
ldi 16, 0xFF
cpi 16, 0xFF
breq PC + 2
cbi _SFR_IO_ADDR(PORTA), PA0
rjmp end
end:
rjmp end
显然,AVR libc中没有定义PC。那我该怎么做呢?谢谢
更新1
我发现了这个问题,发现gnu as的语法是breq.+2
。然而,我得到了和那个问题相同的错误。当我使用avr objdump-d main.o
反汇编时,我确实得到了
74: 01 f0 breq .+0 ; 0x76
这和那个问题的症状是一样的。我将尝试使用链接器脚本,但我没有这方面的经验
更新2
实际上,我发现如果我在breq指令中使用偶数,比如
breq.+2
或breq.+4
,objdump会显示正确的结果。但是,如果我使用奇数,它将变成breq.+0
。有人能解释一下原因吗?好的,答案现在完全重写了。这是我从编译的C代码的objdump
中了解到的。首先,binutils
对程序计数器使用字节寻址,而不是字寻址,并从当前指令之后的指令开始。以下代码对此进行了解释:
#include <avr/io.h>
.section .text
.global main
main:
sbi _SFR_IO_ADDR(DDRA), PA0
sbi _SFR_IO_ADDR(PORTA), PA0
ldi 16, 0xFF
cpi 16, 0xFF
breq .+4 ;; If we are executing here
cbi _SFR_IO_ADDR(PORTA), PA0 ;; This is .+0, will be skipped
cbi _SFR_IO_ADDR(PORTA), PA0 ;; This is .+2, will be skipped
cbi _SFR_IO_ADDR(PORTA), PA0 ;; This is .+4, which will be executed
rjmp end
end:
rjmp end
#包括
.第节.正文
.全球主要
主要内容:
sbi SFR IO地址(DDRA),PA0
sbi SFR IO地址(端口),第0页
本地设计院16号,0xFF
消费物价指数16,0xFF
breq.+4;;如果我们在这里执行
cbi地址(港口),PA0;;这是。+0,将被跳过
cbi地址(港口),PA0;;这是.+2,将被跳过
cbi地址(港口),PA0;;这是+4,将被执行
rjmp端
完:
rjmp端
显然,PC的宽度与相对地址无关。它只影响最大PC值0xFF或0xFFF,因此无论我为哪个AVR平台编译,binutils
都会使用两个字节作为指令
另外,我认为,如果我知道编译器如何工作的唯一方法就是观察它如何工作,那可能意味着糟糕的文档?也许我只是不知道什么时候开始。如果有人看到这一点,你能帮我指出一些关于“这类事情”的有用书籍吗?(我甚至不知道怎么形容)谢谢 8位MCU并不意味着汇编指令被编码为8位操作码。来自ATmega16规范
大多数AVR指令都有一个16位字格式
相反,即使ATmega是8位MCU,使用的指令也被编码为16位操作码。请看“AVR指令集”。这就是程序计数器(PC)行为如此的原因(仅分配给16位/2字节对齐的地址)。如果能够设置为8位/1字节对齐地址,它将尝试执行无效操作码
这里有件事要你做。将上面的示例编译为一个对象文件。然后反汇编文件(使用objdump-D)并查看生成的反汇编。指令的偏移量应该是16位对齐。是的,我发现out.binutils使用2个字节,因为所有指令都生成“16位操作码”。它不是binutils,而是AVR指令集规范。
#include <avr/io.h>
.section .text
.global main
main:
sbi _SFR_IO_ADDR(DDRA), PA0
sbi _SFR_IO_ADDR(PORTA), PA0
ldi 16, 0xFF
cpi 16, 0xFF
breq .+4 ;; If we are executing here
cbi _SFR_IO_ADDR(PORTA), PA0 ;; This is .+0, will be skipped
cbi _SFR_IO_ADDR(PORTA), PA0 ;; This is .+2, will be skipped
cbi _SFR_IO_ADDR(PORTA), PA0 ;; This is .+4, which will be executed
rjmp end
end:
rjmp end