【问题标题】:Why this if section compiled to infinite loop?为什么这个 if 部分编译为无限循环?
【发布时间】: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,而不是whilefor。编译器引入的无限循环表明if 的 then 子句中存在一些未定义的行为或隐藏的无限循环(例如,在 cmemclr 内部)。
  • StrEntry *entry 什么是StrEnrty?是男人吗?
  • @wildplasser 这是一个结构体。

标签: c assembly arm


【解决方案1】:

cmemclr 有缺陷。根据对问题的编辑,cmemclr 是:

static inline void cmemclr(void *buf, u32 size)
{
    u8 *dst = (u8*)buf;

    while(--size >= 0){
        dst[size] = 0;
    }
}

由于size 的类型u32 可能是无符号的,所以--size &gt;= 0 始终为真。代码进入无限循环。

编辑问题前的回答

一种可能是您显示的汇编代码不完整,当前显示为b 3464c0 的内容稍后将解析为另一个地址。

假设程序集是正确的,并且不是等待进一步链接解析的不完整占位符,编译器已将 if 语句中的代码优化为无限循环,因为该语句内部存在未定义的行为(因此是无限循环)循环是允许的行为)或者因为语句中的某些内容执行了无限循环。

由于您没有提供if 语句中使用的例程或宏的实现或规范,因此无法进行进一步诊断。

【讨论】:

    猜你喜欢
    • 2020-08-08
    • 1970-01-01
    • 2018-03-17
    • 1970-01-01
    • 2020-07-12
    • 2021-08-16
    • 2018-01-13
    相关资源
    最近更新 更多