【问题标题】:GCC generated assembly equivalent to continue statement in CGCC 生成的程序集等同于 C 中的 continue 语句
【发布时间】:2010-03-01 10:20:47
【问题描述】:

当在 C 代码的循环中使用 continue 语句时,GCC 会在循环块结束之前创建一个带有 nop 指令的新标签并跳转到它,而不是跳转到循环块本身的末尾。比如下面的C代码

for (i=0; i<10; i++) {
    puts("blah\n");
    if (i < 10) continue;
    puts("This shouldn't be printed.\n");
}

产生以下 ASM 等效项(使用 gcc -S ):

    movl    $0, 28(%esp)
    jmp L2
L5:
    movl    $LC0, (%esp)
    call    _puts
    cmpl    $9, 28(%esp)
    jle L7
L3:
    movl    $LC1, (%esp)
    call    _puts
    jmp L4
L7:
    nop
L4:
    incl    28(%esp)
L2:
    cmpl    $9, 28(%esp)
    jle L5

(插入了 if (i

我的问题是,为什么不直接跳到 L4 呢? IMO 我们也可以跳到 L4,我错过了什么吗?

【问题讨论】:

    标签: c gcc assembly


    【解决方案1】:

    您所描述的是优化。果然,如果您告诉 gcc 进行优化(-O1 就足够了),它会完全按照您的描述进行。

    【讨论】:

    • 感谢您的快速回复! -O1 成功了,尽管优化后的程序流程现在看起来不太直观——除非我弄错了,现在循环似乎部分展开了。我现在很好奇是否有任何动机使用 nop 指令创建标签。是否存在这种方法可以防止直接跳转到 L4 时发生的事情的情况?
    • 出于调试目的,您可以在 L7 标签中设置断点 - 如果没有继续用例,则很难中断。
    • @susmits:使用 -O1 程序集不那么冗长,但循环没有展开(使用 -O3 您可以看到展开的版本 - 请注意它甚至不包括 i
    【解决方案2】:

    我的猜测是它是某种跳过代码修复序列的占位符。也许nop 有时会被替换为将寄存器存储到堆栈或类似的指令。

    但为了获得更多证据,找到一个将nop 替换为其他内容的示例会有所帮助。

    【讨论】:

    • 我想大概就是这样。在这种情况下,涉及的变量非常少,以至于“继续”时寄存器中的变量集与第二次放置后寄存器中的变量集相同。如果不是这种情况,那么在 L7 之后将是同步它们的代码。当然,如果循环中有多个“继续”,那么每个都必须在跳转之前将自己同步到正确的 L7 状态。
    • 另一方面,将这样的代码放在与 continue 语句关联的块中效率极低,所以我猜无论如何这种情况很少见。
    • 请记住,susmits 已隐式请求低效代码(通过未指定 -O);-)
    猜你喜欢
    • 1970-01-01
    • 2017-04-29
    • 1970-01-01
    • 2014-01-07
    • 1970-01-01
    • 1970-01-01
    • 2010-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多