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

问题描述 投票:0回答:1

考虑以下 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(字节地址)范围应该是 0x0000002e4(包含)到 0x000002ee(不包含)。换句话说,我认为第 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

我们将端口D的DDR地址加载到r24和r25中,然后将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行从0x0000002e6开始,第14行从0x0000002f0开始,但这似乎不对。应该分别是 0x0000002e4 和 0x0000002ee。

更奇怪的是,未使用的

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 行从 0x0000008a 开始(第一个

LDI
指令,将 DDRD 加载到 r24 和 r25),第 14 行从 0x00000094 开始,这是正确的。

如果我从未使用的函数体中删除其中一个

_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 架构。

c gcc avr avr-gcc dwarf
1个回答
0
投票

这似乎是 GCC 11.1.0 中的回归。此后该问题已得到修复。我升级到 GCC 13.2.0 并且无法重现该问题,所以一切都好。

© www.soinside.com 2019 - 2024. All rights reserved.