【问题标题】:Does Delphi compiler perform optimization?Delphi 编译器是否执行优化?
【发布时间】:2010-11-03 02:18:13
【问题描述】:

我正在使用 Delphi 7 IDE。 Delphi 编译器是否像 C++ 编译器在以下链接中所做的那样优化代码?

http://msdn.microsoft.com/en-us/library/aa366877(VS.85).aspx

WCHAR szPassword[MAX_PATH];
// Retrieve the password
if (GetPasswordFromUser(szPassword, MAX_PATH))    
   UsePassword(szPassword);
// Clear the password from memory
SecureZeroMemory(szPassword, sizeof(szPassword));

如果在此示例中调用 ZeroMemory 而不是 SecureZeroMemory,编译器可以优化调用,因为在超出范围之前不会读取 szPassword 缓冲区。密码将保留在应用程序堆栈中,在那里它可以在故障转储中捕获或被恶意应用程序探测。

【问题讨论】:

    标签: delphi optimization compiler-construction compiler-optimization


    【解决方案1】:

    是的,Delphi 当然会执行优化。但是,它不会执行 SecureZeroMemory 函数旨在规避的优化。在 Delphi 中不需要使用该功能;只需使用普通的旧ZeroMemory,甚至FillChar。它们不是宏,它们不会做任何被 Delphi 识别为可以优化的未使用的赋值语句。

    【讨论】:

      【解决方案2】:

      Delphi默认进行代码优化,你可以在Project > Options > Compiler中禁用它。

      Delphi 帮助提供了一些关于使用何种优化类型的提示:

      $O 指令控制代码优化。在 {$O+} 状态下,编译器会执行一些代码优化,例如将变量放入 CPU 寄存器、消除公共子表达式以及生成归纳变量。

      它还声明“编译器不会执行任何“不安全”的优化”,但从某种意义上说,它们不会改变执行路径,而不是从安全的角度来看。

      【讨论】:

        【解决方案3】:

        Delphi 确实优化了代码(它是一种现代且优秀的编译器)。另一个优化删除行的例子是:

        SomeFunction();  // Set breakpoint here, then step (F10)
        myInt := 7;      // Next line will not hit this...
        myInt := 13;     // ...but will instead skip to here
        

        我喜欢通过在我项目的每个 .pas 文件中添加 {$I MyProjectOptions.inc} 来确保优化处于正确的状态(并且不会意外地打开或关闭)。它位于单位名称下方(文件顶部)。在“MyProjectOptions.inc”中,您只需添加以下代码:

        // Is this a debug or non-debug build?
        {$IF Defined(DEBUG)}
            {$O-}   // Turn optimization off
        {$ELSEIF Defined(NDEBUG)}
            {$O+}   // Ensure optimisation is on
        {$IFEND}
        

        最后,确保您已在 Project > Options > Diectories/Conditionals 的条件定义部分定义了“DEBUG”和“NDEBUG”(或旧版本 Delphi 中的等效项)。

        【讨论】:

          【解决方案4】:

          我不相信编译器会消除这样明显的死代码。我从来没有遇到过在代码上设置断点的问题,这些代码本来可以作为冗余而被删除。

          【讨论】:

          • 其实我有。根本没有调用的方法,不会包含在您的 .EXE 中,并且您放在那里的断点不会显示为可访问的。
          • 情况不同,@Jeroen。 Loren 正在讨论 可达的代码,但如果执行则不会产生任何影响。足够聪明的编译器可以识别出代码没有效果并忽略它。一个很好的例子是问题中的那个,其中密码数组在被清除后从未使用过。如果编译器知道将ZeroMemory 视为赋值语句,并且设置为优化以后不再使用的赋值,则可能会消除对ZeroMemory 的调用。 SecureZeroMemory 只是一个编译器不知道可以省略的新函数。
          【解决方案5】:

          对于某些场景,编译器可以检测代码是否不可达并消除代码。

          例如,编译器正确地消除了以下代码的“无法访问”部分。
          它不会为该行生成代码,因此:

          1. 所以没有蓝色项目符号表示有代码
          2. 该行上的断点将在视觉上标记为“不可到达”

          刚刚在 Delphi XE 中进行了测试,但较旧的 Delphi 版本具有类似的行为。

          program Project1;
          
          {$APPTYPE CONSOLE}
          
          uses
            SysUtils;
          
          procedure Test;
          begin
            if (True = False) then
              Writeln('Unreachable')
            else
              Writeln('Reachable');
          end;
          
          begin
            try
              Test();
            except
              on E: Exception do
                Writeln(E.ClassName, ': ', E.Message);
            end;
          end.
          

          需要相当长的时间来了解代码级别和喜欢级别的优化器何时(或何时不)启动。

          例如:当您打开优化时,编译器也会在变量不使用时立即消除它们。
          有时,它甚至消除了全局符号。 Danny Thorpe(前 Delphi 编译器工程师和首席科学家)曾经写过 magic method Touch 来防止这种情况发生。
          只需在方法结束时调用此 Touch 方法即可在调试期间欺骗优化器:

          procedure Touch(var arg);
          begin
          end;
          

          --杰罗恩

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-07-31
            • 1970-01-01
            • 2016-05-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多