gpt4 book ai didi

delphi - 跳出 block 时是否有一种安全的方法来清理基于堆栈的代码?

转载 作者:行者123 更新时间:2023-12-03 19:23:23 26 4
gpt4 key购买 nike

我一直在研究 Issue 14在 PascalScript 脚本引擎上,使用 Goto 命令跳出 Case block 会产生编译器错误,即使这是完全有效(如果丑陋)的 Object Pascal 代码。

结果编译器中的 ProcessCase 例程调用 HasInvalidJumps,它会扫描任何在 Case block 之外的 Goto,如果找到,则会给出编译器错误。如果我评论检查,它编译得很好,但最终在运行时崩溃。字节码的反汇编说明了原因。我已经用原始脚本代码对其进行了注释:

[TYPES]
<SNIPPED>
[VARS]
Var [0]: 27 Class TFORM
Var [1]: 28 Class TAPPLICATION
Var [2]: 11 S32 //i: integer
[PROCS]
Proc [0] Export: !MAIN -1
{begin}
[0] ASSIGN GlobalVar[2], [1]
{ i := 1;}
[15] PUSHTYPE 11(S32) // 1
[20] ASSIGN Base[1], GlobalVar[2]
{ case i of}
[31] PUSHTYPE 25(U8) // 2
{ 0:}
[36] COMPARE into Base[2]: [0] = Base[1]
[57] COND_NOT_GOTO currpos + 5 Base[2] [72]
{ end;}
[67] GOTO currpos + 41 [113]
{ 1:}
[72] COMPARE into Base[2]: [1] = Base[1]
[93] COND_NOT_GOTO currpos + 10 Base[2] [113]
{ goto L1;}
[103] GOTO currpos + 8 [116]
{ end;}
[108] GOTO currpos + 0 [113]
{ end; //<-- case}
[113] POP // 1
[114] POP // 0
{ Exit;}
[115] RET
{L1:
Writeln('Label L1');}
[116] PUSHTYPE 17(WideString) // 1
[121] ASSIGN Base[1], ['????????']
[144] CALL 1
{end.}
[149] POP // 0
[150] RET
Proc [1]: External Decl: \00\00 WRITELN

“转到 L1;” 103 处的语句跳过了 113 和 114 处的清理弹出,这使堆栈处于无效状态。

Delphi 对此没有任何问题,因为它不使用计算堆栈。然而,PascalScript 就没有那么幸运了。我需要一些方法来完成这项工作,因为这种模式在一些来自更简单系统的遗留脚本中非常常见,而我已经翻译成 PascalScript 并且需要能够支持的控制结构的方式很少。

任何人都知道如何修补 codegen 以便正确清理堆栈?

最佳答案

IIRC 经典帕斯卡的 goto 规则是:

  • 只允许跳出 block (在树的“相同”分支上从较高的嵌套级别到较低的嵌套级别)
  • 从本地程序到他们的 parent 。

  • 后者从未得到 Borland 派生的 Pascals 的支持,但第一个仍然成立。

    因此,您需要像 Martin 所说的那样生成退出代码,但可能它可以用于多个 block 级别,因此您不能为每个 goto 生成可能的代码,但必须生成代码(以退出所需 block 的精确数量)。

    一个典型的测试模式是使用 goto 从多个嵌套的 if(可能在一个循环中)退出,因为这是一个经典的微优化,至少在 D7 之前速度更快。

    请记住,if 评估及其分支的 begin..end block 可能已生成需要清理的临时文件。

    ---------- 稍后添加

    我认为代码生成器需要一种方法来遍历 goto 及其端点之间的范围,并在此过程中为 block 生成相关的退出代码。这样,修复程序适用于一般情况,而不仅仅是此示例。
    由于您只能跳出范围,而不能进入范围,因此可能并不那么难。

    IOW 生成的东西相当于(对于假设的双案例 block )

    Lgoto1gluecode:
    //退出代码第一个 block
    流行x
    流行音乐
    //退出代码第一个 block
    流行音乐
    流行音乐B
    转到 real_goto_destination

    可以进行额外的分析。例如。如果范围只有一个,并且已经有清理退出标签,则可以直接跳转。如果您确定上述 pop 只是丢弃的值(而不是保存寄存器),您可以通过 add $16,%esp(4*4 字节值)等立即执行它们。

    关于delphi - 跳出 block 时是否有一种安全的方法来清理基于堆栈的代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1024445/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com