Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Gcc 如何在AVR libc中访问PC指针(使用汇编)?_Gcc_Assembly_Linker_Branch_Avr - Fatal编程技术网

Gcc 如何在AVR libc中访问PC指针(使用汇编)?

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

我正在尝试使用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(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