【发布时间】:2018-10-27 20:04:42
【问题描述】:
下面的C代码:
s32 load_string(char* string_new, char const* string_orign)
{
StrEntry *entry = search_str_entry(string_orign);
u8 buff_b[32];
u16 buff_u[32];
s32 read_size = 0;
void *str_file = 0;
if (entry != 0){
cmemclr(buff_b, 32);
cmemclr(buff_u, 64);
sprintf(&buff_b[0], "c:/data/%03d.str", entry->fid);
c2w(&buff_u[0], &buff_b[0], 32);
if (TryOpenFile(&str_file, buff_u, OPEN_MODE_READ) == 0){
cmemclr(string_new, 256);
TryReadFile(&read_size, str_file, entry->offset, string_new, entry->size);
CloseFile(str_file);
return (s32)entry->size;
}
}
return 0;
}
这个函数的反汇编:
003464ac <load_string>:
3464ac: e92d4010 push {r4, lr}
3464b0: e1a00001 mov r0, r1
3464b4: ebffffda bl 346424 <search_str_entry>
3464b8: e3500000 cmp r0, #0
3464bc: 08bd8010 popeq {r4, pc}
3464c0: eafffffe b 3464c0 <load_string+0x14>
我们可以看到if部分变成了无限循环,为什么?
我使用 -Os 优化选项来编译这段代码。 gcc 版本是
gcc 版本 8.1.0(devkitARM 版本 49)。
编辑:
cmemclr 是一个简单的内联函数:
static inline void cmemclr(void *buf, u32 size)
{
u8 *dst = (u8*)buf;
while(--size >= 0){
dst[size] = 0;
}
}
【问题讨论】:
-
如果前面的比较表明它等于 0,
popeq指令将返回r0中的值。本质上它是将代码重写为do { ... if (!search_str_entry(...)) return 0; } while(1);。如果它在第一次尝试时返回零,这将保存一条指令,即使在第二次尝试时返回零,也会中断,并在第二次尝试后为每次尝试获取一条额外的指令。我不知道为什么 gcc 会决定这是一个很好的权衡,但在某些情况下它会。 -
请使用
-S编译,让编译器生成程序集并向我们展示该文件。 “无限循环”可能只是一个未填充的重定位。 -
@supercat:第二次尝试是什么?源代码中没有循环。它只是一个
if,而不是while或for。编译器引入的无限循环表明if的 then 子句中存在一些未定义的行为或隐藏的无限循环(例如,在cmemclr内部)。 -
StrEntry *entry什么是StrEnrty?是男人吗? -
@wildplasser 这是一个结构体。