请教一个关于编译器优化代码的问题(50分)

  • 主题发起人 主题发起人 sy0116
  • 开始时间 开始时间
S

sy0116

Unregistered / Unconfirmed
GUEST, unregistred user!
最近在写一个API Hook程序,因为一些特殊的原因我的替代函数不能够直接用Exit();返回,必须用内嵌汇编来返回,而且返回时不弹出堆栈,代码如下:
function MyCreateA(lpApplicationName: PAnsiChar; lpCommandLine: PAnsiChar;
lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer;
lpCurrentDirectory: PAnsiChar; const lpStartupInfo: TStartupInfo;
var lpProcessInformation: TProcessInformation): BOOL; stdcall;
begin
if (lpApplicationName[0] = 'c') or (lpApplicationName[0] = 'C') then
begin
MessageBoxA(0,演示程序','演示',0);
//lpApplicationName := nil;这两句代码根本就没被编译
//lpCommandLine := nil;
//返回
asm
mov lpApplicationName,0//这样写就可以
mov lpCommandLine,0
pop ebp
ret
end;
end;
end;
这断代码的问题我已经在上面的注释中说明了,我觉得似乎是Delphi的编译器在编译时把那两句赋值代码给优化掉了,我用OD跟踪调试过,发现那两句代码根本就没有编译出来,请问有什么办法可以设置一下编译器让他不要把那两句代码给优化掉呢?
 
不太懂你的东西,可能delphi中有某个编译开关可以达到你的要求。
转一个文章,也许只需关闭掉delphi的编译优化选项即可,怎么关,下面有

《Delphi下深入Windows核心编程》(附录A Delphi编译指令说明)
摘抄人:麻子 qq:71892967

Delphi快速高小的编译器主要来自Object PASCAL的严谨,使用Delphi随时都在与编译器交流,大部分情况下不需要干涉编译器的运行,但是有时也需要对编译器进行必要的设置。

**********************************************************************************************

A.1 使用编译设置对话框

编译器的编译指令是用于指定编译器对项目编译过程的动作和行为。可以通过[Project]->[Options]->[Complier]选项页进行设置,绝大部分的编译环境都可以通过这一对话框进行调整,他包含了对代码、语法、调试信息等的设置。

1.代码设置(Code Generation)

Optimization: 代码优化开关

Aligned record fields: 字对齐数据。这个编译指令能够在变量和类型化常量的字节对齐和字对齐之间进行切换,其作用是全局的。

Stack frames: Windows 堆栈帧。其作用域是局部的,他使编译器成为远端过程和函数生成特定的开头和结尾代码。这个指令用于Windows 3.0的实模式,对所有Delphi应用程序他应该是关闭的。

Pentium-safe FDIV: Pentium安全FDIV检查。此指令能够在Pentium处理器中指定编译器是否创建能够检测和使用有缺陷的浮点除法指令的代码。

2.运行期错误(Runtime Errors)

Range Checking: 范围检查。这个指令的作用范围是局部的,用于控制范围检验代码的生成。

I/O Checking: I/O检查。这个指令的作用域为局部,用来生成对一个文件的输入和输出过程和调用结果进行检查的代码。一般应该使其功能打开。

Overflos Checking: 溢出检查。其作用是生成对算术溢出检查的代码。

3.语法设置(Syntax Optings)

Strict Var- strings: 静态变量串开关。用来控制对以变量参数形式传递的串的类型检查。

Comlete Boolean Eval: 完全布尔表达量判定。用于执行强制的完整表达式判定。完全布尔量判定,有可能导致系统崩溃,所以一般不使用他。

Extended Syntax: 扩展语法开关。他能允许或禁止Delphi的扩展语法。

Typed @ Operator: 类型化的@运算符检查。应用于局部的变量引用上,控制@运算符返回的指针值类型。

Open Parameters: 开放参数开关。用于控制使用String关键字声明的变量参数。开放参数允许将大小不一的串变量传递到同一个过程或函数中,一般在汇编中会使用到。

Huge Strings: 字符串类型开关。用于控制Ansistring和Shortstring类型的切换。当打开时符合Ansistring,关闭时符合Shortstring。

Assignable Typed Constants: 可分配类型常量。用于向下与Delphi 1.0兼容。

4.调试(Debugging)

Debug Information: 调试信息开关。用于设置是否把调试信息写入以编译的单元文件(.dcu)。

Local Symbols: 局部符号开关。允许或禁止局部符号信息的创建。

Reference Info/Definitions Only: 符号信息开关。用于允许或禁止由Delohi的对象浏览器使用的符号引用信息的生成。

Assertions: 用于控制局部代码的属性。

Use Debug DCUs: 使用或禁止VCL的DCU文件调试。

5.信息(Messages)

Show Hints: 显示暗示。

Show Warnings: 显示警告。

**********************************************************************************************

A.2 使用编译指令

除了使用编译设置对话框对编译器进行设置外,还可以通过编译指令来对编译器进行设置。
对于局部的编译器设置,只有使用编译指令来完成。

对于开关编译指令,通过在编译指令后加入指示开关状态的加号和减号来控制编译器。例如:

{$B+} : 打开完全布尔量检查。
{$Q-} : 关闭溢出检查。

通常,编译指令的作用域是在编译指令后的代码部分,而对于全程的编译指令应该防在单元接口部分的开头。
编译设置对话框的设置都有与之对应的编译指令用于在代码中对编译器进行设置,如下表所示。

设置项 编译指令

Optimizations {$O}

Aligned record fields {$A}

Stack frames {$W}

Pentium-safe FDIV {$U}

Range Checking {$R}

I/O Checking {$I}

Overflow Checking {$Q}

Strict Var-strings {$V}

Comlete Boolean Eval {$B}

Extended Syntax {$X}

Typed @ Operator {$T}

Open Parameters {$P}

Huge Strings {$H}

Assertions typed constants {$J}

Debug information {$D}

Local sysnbols {$L}

在这些编译指令以外还有一些非常有用的编译指令。
$R Filename : 这个编译指令是最为常用的编译指令,他是资源文件编译指令,用于指定连接到执行文件和库的资源文件,例如在工程文件(.dpr)中会有{$R *.RES}的编译指令,表明把后缀为 .RES的与工程文件同名的资源文件连接入执行文件,也可以指定一个资源文件,资源文件的使用对于编写Windows程序来说是很重要的基础。

$I Filename :这个编译指令功能类似于C语言的#Include , 用于指定编译时包括的文件。

**********************************************************************************************

A.3 使用条件编译指令

条件编译指令是非常重要的编译指令,他控制着在不同条件下(例如,不同的操作系统)产生不同的代码。条件编译指令是包含在
注释括号之内的,如下表所示。

条件编译指令 含义

$DEFINE 用于定义一个条件符号,一旦定义,条件符号就为真

$ELSE 与$IFDEF配合使用,如果$IFDEF条件为假,则只对源文件$ELSE后一小部分进行编译

$ENDIF 结束一个以$IF开始的条件段

$IFDEF 对条件符号进行判断,为真则编译源文件

$IFNDEF 对条件符号进行判断,为假则编译源文件

$IFOPT 根据编译开关状态,对源文件编译

$UNDEF 撤消以前的条件符号定义

这些条件编译指令是非常有用的。例如,可以通过开关的状态来控制编译:

{IFOPT R+}
showmessage('Compiled with range-checking');
{$ENDIF}

也可以通过定义条件符号来控制编译:

{$Define s}
……
{$ifdef s}
showmessage('yes');
{$else}
showmessage('no');
{$endif}

他的编译结果是显示'yes',但是如果省去{$Define s}则显示'no'。
在Delphi中已经预定义了一些关键的条件符号,如下表所示。

条件符号 含义

VERxx 编译器版本,XX表示版本,例如:Delphi 1.0 的编译器版本为80、Delphi 5.0 的编译器版本为130

WIN32 是否WIN32的运行环境(Windows 95.98/NT/2000)

CPU386 是否Intel386以上的处理器

CONSOLE 是否控制台程序

Delphi的编译器指令除了以上的指令外还有一些,不过最为常用的指令已经全部介绍完了。对于普通的程序,Delphi是不需要编程者去添加编译器指令的,Delphi已经自动完成,但是要得到高品质的应用程序或者有特殊的要求的程序就必须熟悉Delphi的编译指令。Delphi不仅有最快的编译器而且编译器的功能也非常强大。
 
又刚看到一个,一并转了吧

原创文章 作者:Delphibbs---老人家
如果摘抄请注明作者,谢谢!

只是写给初学者的,请高手指正!以后如果时间允许我会天天写的!

Delphi7.0 预编译指令说明

Delphi快速高效的编译器主要来自Object PASCAL的严谨,使用Delphi随时都在与编译器交流,大部分情

况下不需要干涉编译器的运行,但是有时也需要对编译器进行必要的设置。

********************************************************************************************

**

A.1 使用编译设置对话框

编译器的编译指令是用于指定编译器对项目编译过程的动作和行为。可以通过[Project]->[Options]->

[Complier]选项页进行设置(快捷键:Crtl+Shift+F11),绝大部分的编译环境都可以通过这一对话框进行调

整,他包含了对代码、语法、调试信息等的设置。

1.代码设置(Code Generation)
Optimization: 是否优化代码。包括防止变量到CPU寄存器、合并分解表达式、生成中间变量等,其作用

域是局部的。
如果{$O+}或{$OPTIMIZATION ON},如下
var
I: Integer;
begin
I := 1; //不被编译,也就是说调试的时候,这行没有断点
I := 2;
end;
如果{$O-}或{$OPTIMIZATION OFF},如下
var
I: Integer;
begin
I := 1; //被编译,也就是说调试的时候,这行有断点
I := 2;
end;
缺省:{$O+}{$OPTIMIZATION ON}

Stack frames: Windows 堆栈帧。其作用域是局部的,他使编译器成为远端过程和函数生成特定的开头和

结尾代码。这个指令用于Windows 3.0的实模式,对所有Delphi应用程序他应该是关闭的,一些调试工具

需要此类信息。
如果{$W+}{$STACKFRAMES ON},强制每个过程或函数生成堆帧,查找错误时,编译器需要堆帧帮忙。
如果{$W-}{$STACKFRAMES OFF},Delphi 会只在需要时才产生堆帧。
缺省:{$W-}{$STACKFRAMES OFF}
注:谁知道 Delphi 会在什么时后才产生堆帧,老人家向大家请教了?

Pentium-safe FDIV: Pentium安全FDIV检查。此指令能够在Pentium处理器中指定编译器是否创建能够检

测和使用有缺陷的浮点除法指令的代码。
如果{$U+}{$SAFEDIVIDE ON}自动产生对 Pentium 芯片的 bug 检查代码。
如果{$U-}{$SAFEDIVIDE OFF}不产生对 Pentium 芯片的 bug 检查代码。
缺省:{$U-}{$SAFEDIVIDE OFF}
注:这个已经不再需要了。这批有 bug 的芯片,intel 公司已经基本回收掉了(老人家现在还保留一块,

值钱了!)。

2.运行期错误(Runtime Errors)
Range Checking: 范围检查。这个指令的作用范围是局部的,用于控制范围检验代码的生成。是否对

ShortString、有序类型和Array执行越界检查。打开后增加可执行文件大小、减慢速度,一般在调试阶段

使用
如果{$R+}或{$RANGECHECKS ON},如下
var
aInt: array[0..1] of Integer;
I: Integer;
begin
I := 2;
aInt := 3; //运行时提示 "Range Checking error"
end;
如果{$R-}或{$RANGECHECKS OFF},如下
var
aInt: array[0..1] of Integer;
I: Integer;
begin
I := 2;
aInt := 3; //运行时提示 "Access violation at address ?. Read of address ?."
end; //?=内存地址
缺省:{$R-}{$RANGECHECKS OFF}

I/O Checking: I/O检查。这个指令的作用域为局部,用来生成对一个文件的输入和输出过程和调用结果

进行检查的代码。一般应该使其功能打开。
如果{$I+}或{$IOCHECKS ON},EInOutError检查,一旦发生I/O错误时,将会触发一个EInOutError的例外


如果{$I-}或{$IOCHECKS OFF}程序执行时发生过I/O操作错误(例如检测文件是否存在函数),程序设定师

必须自行检查IOResult这个公用变量的值,如果是零,表示没有错误。IOResult函数在System.pas
缺省:{$I+}{$IOCHECKS ON}

Overflos Checking: 溢出检查。其作用是生成对算术溢出检查的代码。打开后增加可执行文件大小、减

慢速度,一般在调试阶段使用
如果{$Q+}或{$OVERFLOWCHECKS ON},如下
var
B: Byte;
begin
B := 255; //运行时提示 "Integer Overflos."
Inc(B);
end;
如果{$Q-}或{$OVERFLOWCHECKS OFF},如下
var
B: Byte;
begin
B := 255; //运行时 B := 0;
Inc(B);
ShowMessage(IntToStr(B));
end;
缺省:{$Q-}{$OVERFLOWCHECKS OFF}
 
这两篇我都看过了,但是还没找到办法,不过这个问题我已经通过别的途径绕过去了
 
后退
顶部