通过AVR汇编程序"hello world"代码

Tho*_*mas 7 assembly arduino avr-gcc

我正在尝试为Arduino Duemilanove(AVR ATmega328P)编写一些汇编语言.在编译和反汇编C代码的同时学习汇编语言,我得到了:

(用AVR_GCC编译)

int main() {
  volatile int a = 0;
  while (1) {
    ++a;
  }
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

哪个变成了

00000000 <__vectors>:
   0: 0c 94 34 00   jmp 0x68  ; 0x68 <__ctors_end>
   4: 0c 94 51 00   jmp 0xa2  ; 0xa2 <__bad_interrupt>
  ...
  64: 0c 94 51 00   jmp 0xa2  ; 0xa2 <__bad_interrupt>

00000068 <__ctors_end>:
  68: 11 24         eor r1, r1
  6a: 1f be         out 0x3f, r1  ; 63
  6c: cf ef         ldi r28, 0xFF ; 255
  6e: d8 e0         ldi r29, 0x08 ; 8
  70: de bf         out 0x3e, r29 ; 62
  72: cd bf         out 0x3d, r28 ; 61

00000074 <__do_copy_data>:
  74: 11 e0         ldi r17, 0x01 ; 1
  76: a0 e0         ldi r26, 0x00 ; 0
  78: b1 e0         ldi r27, 0x01 ; 1
  7a: e4 ec         ldi r30, 0xC4 ; 196
  7c: f0 e0         ldi r31, 0x00 ; 0
  7e: 02 c0         rjmp  .+4       ; 0x84 <__do_copy_data+0x10>
  80: 05 90         lpm r0, Z+
  82: 0d 92         st  X+, r0
  84: a0 30         cpi r26, 0x00 ; 0
  86: b1 07         cpc r27, r17
  88: d9 f7         brne  .-10      ; 0x80 <__do_copy_data+0xc>

0000008a <__do_clear_bss>:
  8a: 11 e0         ldi r17, 0x01 ; 1
  8c: a0 e0         ldi r26, 0x00 ; 0
  8e: b1 e0         ldi r27, 0x01 ; 1
  90: 01 c0         rjmp  .+2       ; 0x94 <.do_clear_bss_start>

00000092 <.do_clear_bss_loop>:
  92: 1d 92         st  X+, r1

00000094 <.do_clear_bss_start>:
  94: a0 30         cpi r26, 0x00 ; 0
  96: b1 07         cpc r27, r17
  98: e1 f7         brne  .-8       ; 0x92 <.do_clear_bss_loop>
  9a: 0e 94 53 00   call  0xa6  ; 0xa6 <main>
  9e: 0c 94 60 00   jmp 0xc0  ; 0xc0 <_exit>

000000a2 <__bad_interrupt>:
  a2: 0c 94 00 00   jmp 0 ; 0x0 <__vectors>

000000a6 <main>:
  a6: cf 93         push  r28
  a8: df 93         push  r29
  aa: 00 d0         rcall .+0       ; 0xac <main+0x6>
  ac: cd b7         in  r28, 0x3d ; 61
  ae: de b7         in  r29, 0x3e ; 62
  b0: 1a 82         std Y+2, r1 ; 0x02
  b2: 19 82         std Y+1, r1 ; 0x01
  b4: 89 81         ldd r24, Y+1  ; 0x01
  b6: 9a 81         ldd r25, Y+2  ; 0x02
  b8: 01 96         adiw  r24, 0x01 ; 1
  ba: 9a 83         std Y+2, r25  ; 0x02
  bc: 89 83         std Y+1, r24  ; 0x01
  be: fa cf         rjmp  .-12      ; 0xb4 <main+0xe>

000000c0 <_exit>:
  c0: f8 94         cli

000000c2 <__stop_program>:
  c2: ff cf         rjmp  .-2       ; 0xc2 <__stop_program>
Run Code Online (Sandbox Code Playgroud)

我试着理解一些事情:

  1. 什么是.-8或类似的语法?(例如地址0x98或0xAA.)
  2. 在地址80到88(__do_copy_data结尾)的行周围有一些有趣的东西.在我看来,这会将所有程序代码从地址0xC4 加载到RAM中.为什么?
  3. 在__do_clear_bss_start/loop中,我们通过将RAM中的字节设置为0(r1的值)来清除我们刚刚完成的所有工作.为什么?所有这一切终于打电话了main.有什么一般性解释吗?
  4. 为什么不贬低显示.bss,.rodata或其他部分?
  5. 第6a行,为什么SREG被清除了?是不是每次指令都设定为应该是什么?
  6. 第6c和6e行:0xFF和0x08对应的是什么?r28和r29是堆栈指针低和高.
  7. 我玩了一下并添加了一个静态全局变量.为什么我们从0x0100而不是0x0000开始存储在RAM中?
  8. 在第8a行,为什么ldi r17, 1?我们之前做过(只是一个愚蠢的评论).还是可以改变r17的其他东西?
  9. 我们开始将程序在闪存中复制到RAM,从0xC4开始(.bss和其他部分我猜),但是关于1的X的cpi/cpc将使所有闪存复制到所有RAM中.仅仅是编译器的懒惰在.bss部分完成复制时不能停止复制?

old*_*mer 3

点/句点用作指示该指令的地址或位置或与之相关的内容的快捷方式。.+8 表示从此处加 8。您必须考虑指令集和/或汇编器相对于指令集的细微差别。正如来自汇编器的附加信息所示,.-8 将指向do_clear_bss_loop后面八个字节,包括指令本身的两个字节。原始代码可能只有标签,brne do_clear_bss_loop.

很可能是复制数据段;.text基本上是只读的。这是您的代码,它希望存在于该平台上的闪存中。.data不过,是读/写的并且通常初始化为非零值。因此,在断电后,您的初始值需要保存在某个地方,例如闪存中,但在启动实际程序之前,引导程序需要将初始 .data 段值从闪存复制到 RAM 中的实际位置。然后,当程序运行时,它可以根据需要读取和/或修改这些值。

例如:

int x = 5;

main ()
{
    x = x + 1;
}
Run Code Online (Sandbox Code Playgroud)

该值 5 必须位于闪存中,以便从加电开始仅使用闪存来保存非易失性信息。但在您可以读取/写入 x 的内存位置之前,您需要将其存储在 RAM 中,因此某些启动代码会将所有.datasgement 内容从闪存复制到 RAM。

很抱歉对您的问题做出的这么长的解释只是猜测。

.bss是程序中初始化为零的变量。对于该.data细分市场,如果我们有 100 个项目,我们将需要 100 个项目在闪存中。但是.bss如果我们有 100 个项目,我们只需要告诉别人有 100 个项目。我们不需要闪存中的 100 个零,只需将其编译/汇编到代码中即可。

所以

int x = 5;
int y;

int main ()
{
    while(1)
    {
        y = y + x + 1;
    }
}
Run Code Online (Sandbox Code Playgroud)

x位于.data且 5 需要位于非易失性存储中。y 已进入.bss,只需在调用 main 之前将其清零即可符合 C 标准。

当然,您自己可能没有使用全局变量,但可能有其他数据以某种方式使用.data和/或.bss段,因此引导代码在调用之前准备好.data和段,以便您的 C 编程体验达到预期。.bssmain()