为什么AVR-GCC在功能开始处添加“ push r1”指令?

时间:2018-08-22 01:42:23

标签: assembly avr avr-gcc

我正在查看用avr-gcc编译后编写的某些代码的汇编结果。具体来说,我使用-Os选项进行了编译。总的来说,输出是我所期望的,但是我无法理解的是正在发出指令push r1。甚至更奇怪的是,函数末尾的补充指令是pop r0。因此,r1的值已保存,但似乎已还原为r0

根据此处的文档:

https://gcc.gnu.org/wiki/avr-gcc#Register_Layout

寄存器r1总是包含零,但是如果函数将其恢复,则可以使用该寄存器。恢复为ldi r1, 0x0,则无需进行推翻,从我的理解中可以理解。

这是C代码和汇编版本的反汇编示例。它使用-Os进行编译。它有点长,但我必须做一个大函数才能使编译器发出此信号。

C代码:

void mqtt_create_connect(mqtt_parser *p, mqtt_connect_config *cfg){
  uint8_t idx = 0;
  p->buffer[idx++] = MQTT_CTRL_CONNECT << 4;
  idx++; // skip remaining length for now
  p->buffer[idx++] = 0x0;
  p->buffer[idx++] = 0x4;
  p->buffer[idx++] = 'M';
  p->buffer[idx++] = 'Q';
  p->buffer[idx++] = 'T';
  p->buffer[idx++] = 'T';
  p->buffer[idx++] = 0x04; // protocol level 3.1.1
  p->buffer[idx++] = 
    MQTT_CONNECT_FLAG_CLEAN_SESSION;
  push_uint16_t(p, cfg->keepAliveInterval, &idx);
  push_charptr(p, cfg->clientIdentifier, &idx);
  p->bufferIdx = idx;

  // fill in remaining length
  p->buffer[1] = p->bufferIdx - 2;
}

反汇编:

0000006a <mqtt_create_connect>:
  6a:   0f 93           push    r16
  6c:   1f 93           push    r17
  6e:   cf 93           push    r28
  70:   df 93           push    r29
  72:   1f 92           push    r1
  74:   cd b7           in      r28, 0x3d       ; 61
  76:   de b7           in      r29, 0x3e       ; 62
  78:   8c 01           movw    r16, r24
  7a:   fb 01           movw    r30, r22
  7c:   80 e1           ldi     r24, 0x10       ; 16
  7e:   d8 01           movw    r26, r16
  80:   11 96           adiw    r26, 0x01       ; 1
  82:   8c 93           st      X, r24
  84:   11 97           sbiw    r26, 0x01       ; 1
  86:   13 96           adiw    r26, 0x03       ; 3
  88:   1c 92           st      X, r1
  8a:   13 97           sbiw    r26, 0x03       ; 3
  8c:   84 e0           ldi     r24, 0x04       ; 4
  8e:   14 96           adiw    r26, 0x04       ; 4
  90:   8c 93           st      X, r24
  92:   14 97           sbiw    r26, 0x04       ; 4
  94:   9d e4           ldi     r25, 0x4D       ; 77
  96:   15 96           adiw    r26, 0x05       ; 5
  98:   9c 93           st      X, r25
  9a:   15 97           sbiw    r26, 0x05       ; 5
  9c:   91 e5           ldi     r25, 0x51       ; 81
  9e:   16 96           adiw    r26, 0x06       ; 6
  a0:   9c 93           st      X, r25
  a2:   16 97           sbiw    r26, 0x06       ; 6
  a4:   94 e5           ldi     r25, 0x54       ; 84
  a6:   17 96           adiw    r26, 0x07       ; 7
  a8:   9c 93           st      X, r25
  aa:   17 97           sbiw    r26, 0x07       ; 7
  ac:   18 96           adiw    r26, 0x08       ; 8
  ae:   9c 93           st      X, r25
  b0:   18 97           sbiw    r26, 0x08       ; 8
  b2:   19 96           adiw    r26, 0x09       ; 9
  b4:   8c 93           st      X, r24
  b6:   19 97           sbiw    r26, 0x09       ; 9
  b8:   82 e0           ldi     r24, 0x02       ; 2
  ba:   1a 96           adiw    r26, 0x0a       ; 10
  bc:   8c 93           st      X, r24
  be:   1a 97           sbiw    r26, 0x0a       ; 10
  c0:   80 81           ld      r24, Z
  c2:   91 81           ldd     r25, Z+1        ; 0x01
  c4:   1b 96           adiw    r26, 0x0b       ; 11
  c6:   9c 93           st      X, r25
  c8:   1b 97           sbiw    r26, 0x0b       ; 11
  ca:   9c e0           ldi     r25, 0x0C       ; 12
  cc:   99 83           std     Y+1, r25        ; 0x01
  ce:   1c 96           adiw    r26, 0x0c       ; 12
  d0:   8c 93           st      X, r24
  d2:   62 81           ldd     r22, Z+2        ; 0x02
  d4:   73 81           ldd     r23, Z+3        ; 0x03
  d6:   ae 01           movw    r20, r28
  d8:   4f 5f           subi    r20, 0xFF       ; 255
  da:   5f 4f           sbci    r21, 0xFF       ; 255
  dc:   c8 01           movw    r24, r16
  de:   0e 94 00 00     call    0       ; 0x0 <push_charptr>
  e2:   89 81           ldd     r24, Y+1        ; 0x01
  e4:   f8 01           movw    r30, r16
  e6:   ef 5b           subi    r30, 0xBF       ; 191
  e8:   ff 4f           sbci    r31, 0xFF       ; 255
  ea:   80 83           st      Z, r24
  ec:   82 50           subi    r24, 0x02       ; 2
  ee:   f8 01           movw    r30, r16
  f0:   82 83           std     Z+2, r24        ; 0x02
  f2:   0f 90           pop     r0
  f4:   df 91           pop     r29
  f6:   cf 91           pop     r28
  f8:   1f 91           pop     r17
  fa:   0f 91           pop     r16
  fc:   08 95           ret

push r1pop r0的目的是什么?

1 个答案:

答案 0 :(得分:3)

这里有两个技巧。

首先,gcc需要在堆栈上保留一个字节的空间—为uint8_t idx; 堆栈指针需要递减并保存回SPH:SPL。但是,此两{out”操作可能会因灾难性的结果而中断。因此,必须用cli / sei对包裹-额外的代码和时间。 按下 any 寄存器会自动产生相同的结果,并使用短代码。

第二个:如您所注意,按照avr-gcc / avr-libc约定,r1__zero_reg__,在任何C代码中都假定始终为零。 因此,push r1不仅为idx保留了空间,而且还通过0对其进行了初始化。

函数结尾中的

pop r0恢复堆栈指针。按照约定,r0__temp_reg__,可以被任何C代码破坏的临时寄存器。因此,编译器可以随时销毁int内容。

p.s。该函数不会更改r1,因此无需还原r1