简单AVR程序(GCC制作)的DWARF行号数据似乎不对

qfe3c7zg  于 2023-10-16  发布在  其他
关注(0)|答案(1)|浏览(102)

考虑以下AVR程序:

#define F_CPU 500000ul

#include <avr/io.h>
#include <util/delay.h>

// Not used, but it has significance. I suspect its presence is causing some undesired behaviour in debug info
void do_nothing() {
    _delay_ms(300);
    _delay_ms(300);
}

int main(void) {
    DDRD = 0xFF; // Line 13
    PORTD = 0x00; // Line 14
    PORTD = 0x01; // Line 15
    PORTD = 0x00; // Line 16

    while (1) {

    }
}

很直接。如果我们在禁用优化并启用调试信息(-ggdb)的情况下编译,并让GDB反汇编操作码,我们会得到main()的以下指令:

0x000002dc <main+0>: push r28
0x000002de <main+2>: push r29
0x000002e0 <main+4>: in r28, 0x3d
0x000002e2 <main+6>: in r29, 0x3e
0x000002e4 <main+8>: ldi r24, 0x2A
0x000002e6 <main+10>: ldi r25, 0x00
0x000002e8 <main+12>: ldi r18, 0xFF ; 255
0x000002ea <main+14>: movw r30, r24
0x000002ec <main+16>: st Z, r18
0x000002ee <main+18>: ldi r24, 0x2B
0x000002f0 <main+20>: ldi r25, 0x00
0x000002f2 <main+22>: movw r30, r24
0x000002f4 <main+24>: st Z, r1
0x000002f6 <main+26>: ldi r24, 0x2B
0x000002f8 <main+28>: ldi r25, 0x00
0x000002fa <main+30>: ldi r18, 0x01 ; 1
0x000002fc <main+32>: movw r30, r24
0x000002fe <main+34>: st Z, r18
0x00000300 <main+36>: ldi r24, 0x2B
0x00000302 <main+38>: ldi r25, 0x00
0x00000304 <main+40>: movw r30, r24
0x00000306 <main+42>: st Z, r1
0x00000308 <main+44>: rjmp .-2 ;  0x308 <main+44> (offset in GDB is byte offset, not word offset, so RJMP .-2 is actually RJMP .-1 (infinite loop))

现在,让我们关注第13行。除非我弄错了,该行的PC(字节地址)范围应该是0x 000002 e4(包括)到0x 000002 ee(不包括)。换句话说,我相信第13行由以下指令子集组成:

0x000002e4 <main+8>: ldi r24, 0x2A
0x000002e6 <main+10>: ldi r25, 0x00
0x000002e8 <main+12>: ldi r18, 0xFF ; 255
0x000002ea <main+14>: movw r30, r24
0x000002ec <main+16>: st Z, r18

我们在r24和r25中加载端口D的DDR地址,然后将0xFF加载到r18中,然后将DDR地址复制到Z寄存器,然后将r18的值写入该DDR。所有这些都是为了13号线,除非我弄错了。
问题是DWARF的数据不符合我的观点。从ELF转储DWARF数据(使用dwarfdump),我们得到以下行号信息:

0x000002c8  [  10, 1] NS uri: "main.c"
0x000002de  [  12,18] NS
0x000002e6  [  13, 5] NS <-- This seems wrong...
0x000002ea  [  13,10] NS
0x000002f0  [  14, 5] NS <-- and this...and so on
0x000002f4  [  14,11] NS
0x000002f8  [  15, 5] NS
0x000002fc  [  15,11] NS
0x00000302  [  16, 5] NS
0x00000306  [  16,11] NS
0x0000030a  [  18,11] NS DI=0x1
0x0000030c  [  18,11] NS ET

因此,根据DWARF数据,main.c的第13行从0x 000002 e6开始,第14行从0x 000002 f0开始,但这似乎不正确。它应该分别为0x 0000002 e4和0x 0000002 ee。
更奇怪的是,未使用的do_nothing()函数似乎在其中发挥了作用。如果我把这个函数一起删除,DWARF数据是正确的:

0x00000082 <main+0>: push r28
0x00000084 <main+2>: push r29
0x00000086 <main+4>: in r28, 0x3d
0x00000088 <main+6>: in r29, 0x3e
0x0000008a <main+8>: ldi r24, 0x2A
0x0000008c <main+10>: ldi r25, 0x00
0x0000008e <main+12>: ldi r18, 0xFF ; 255
0x00000090 <main+14>: movw r30, r24
0x00000092 <main+16>: st Z, r18
0x00000094 <main+18>: ldi r24, 0x2B
...
0x00000082  [  12,18] NS uri: "main.c"
0x0000008a  [  13, 5] NS
0x0000008e  [  13,10] NS
0x00000094  [  14, 5] NS
0x00000098  [  14,11] NS
0x0000009c  [  15, 5] NS
0x000000a0  [  15,11] NS
0x000000a6  [  16, 5] NS
0x000000aa  [  16,11] NS
0x000000ae  [  18,11] NS DI=0x1
0x000000b0  [  18,11] NS ET

在那里,第13行从0x 000008 a开始(第一个LDI指令,将DDRD加载到r24和r25中),第14行从0x 0000094开始,这是正确的。
如果我从未使用的函数体中删除一个_delay_ms()调用,情况也是如此:

void do_nothing() {
    _delay_ms(300);
    // By removing the other _delay_ms() call, the debug info is no longer incorrect.
}

你知道出什么事了吗
我使用GCC 11.1.0,用于AVR架构。

zy1mlcev

zy1mlcev1#

这似乎是GCC 11.1.0中的一个回归。后来就修好了。我升级到GCC 13.2.0,无法重现这个问题,所以一切都很好。

相关问题