已跳过函数本地静态对象的构造函数调用



我已经编写了以下函数:

inline void putc(int c)
{
static Cons_serial serial;
if (serial.enabled())
serial.putc(c);
}

其中Cons_serial是一个具有非平凡默认构造函数的类。我相信确切的类定义在这里并不重要,但你可以纠正我的错误。我正在使用以下标志使用g++为x86 32位进行编译:-m32 -fno-PIC -ffreestanding -fno-rtti -fno-exceptions -fno-threadsafe-statics -O0,为putc生成的汇编代码如下所示:

00100221 <_Z4putci>:
100221:       55                      push   %ebp
100222:       89 e5                   mov    %esp,%ebp
100224:       83 ec 08                sub    $0x8,%esp
100227:       b8 f8 02 10 00          mov    $0x1002f8,%eax
10022c:       0f b6 00                movzbl (%eax),%eax
10022f:       84 c0                   test   %al,%al
100231:       75 18                   jne    10024b <_Z4putci+0x2a>
100233:       83 ec 0c                sub    $0xc,%esp
100236:       68 f0 02 10 00          push   $0x1002f0
10023b:       e8 36 fe ff ff          call   100076 <_ZN11Cons_serialC1Ev>
100240:       83 c4 10                add    $0x10,%esp
100243:       b8 f8 02 10 00          mov    $0x1002f8,%eax
100248:       c6 00 01                movb   $0x1,(%eax)
10024b:       83 ec 0c                sub    $0xc,%esp
10024e:       68 f0 02 10 00          push   $0x1002f0
100253:       e8 4c fe ff ff          call   1000a4 <_ZNK11Cons_serial7enabledEv>
100258:       83 c4 10                add    $0x10,%esp
10025b:       84 c0                   test   %al,%al
10025d:       74 13                   je     100272 <_Z4putci+0x51>
10025f:       83 ec 08                sub    $0x8,%esp
100262:       ff 75 08                pushl  0x8(%ebp)
100265:       68 f0 02 10 00          push   $0x1002f0
10026a:       e8 41 fe ff ff          call   1000b0 <_ZN11Cons_serial4putcEi>
10026f:       83 c4 10                add    $0x10,%esp
100272:       90                      nop
100273:       c9                      leave  
100274:       c3                      ret   

在执行过程中,100231的跳转是在函数第一次运行时执行的,因此Cons_serial永远不会被调用。为什么x86程序集的知识值得怀疑,导致该程序集的指令实际上是做什么的?我认为这段代码是为了在随后的函数调用中跳过构造函数调用。但是,为什么在函数第一次运行时也会跳过它呢?

编辑:这段代码是我正在编写的内核的一部分,我怀疑根本原因可能是我的内核的.bss部分有问题,这是我使用的链接器脚本:

OUTPUT_FORMAT("elf32-i386")
ENTRY(_start)
SECTIONS
{
. = 0x100000;
.text : AT(0x100000) {
*(.text)
}
.data : SUBALIGN(2) {
*(.data);
*(.rodata*);
}
.bss : SUBALIGN(4) {
__bss_start = .;
*(.COMMON);
*(.bss*)
. = ALIGN(4);
__bss_end = .;
}
/DISCARD/ : {
*(.eh_frame)
*(.comment)
}
}

这是我用来将.bss部分归零的代码:

extern uint32_t __bss_start;
extern uint32_t __bss_end;
void zero_bss()
{
for (uint32_t bss_addr = __bss_start; bss_addr < __bss_end; ++bss_addr)
*reinterpret_cast<uint8_t *>(bss_addr) = 0x00;
}

但当zero_bss运行时,__bss_start0x27__bss_end0x101,这根本不是我想要的(BSS毕竟应该包含地址0x1002f8(。

我现在已经解决了,@user3124812的提示让我达到了目标,再次感谢。我的zero_bss代码有故障,我需要从链接器脚本中获取__bss*标记的地址,即:

extern uint8_t __bss_start;
extern uint8_t __bss_end;
void zero_bss()
{
uint8_t *bss_start = reinterpret_cast<uint8_t *>(&__bss_start);
uint8_t *bss_end = reinterpret_cast<uint8_t *>(&__bss_end);
for (uint8_t *bss_addr = bss_start; bss_addr < bss_end; ++bss_addr)
*bss_addr = 0x00;
}

现在一切正常。

最新更新