- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这个问题基于previous ,但这仅供引用。
我已经设法让它工作,但是,我发现了一些我不清楚的东西,所以如果有人能解释以下行为,那就太棒了。
我有以下类(class):
type
TMyObj = class
published
procedure testex(const s: string; const i: integer);
end;
procedure TMyObj.testex(const s: string; const i: integer);
begin
ShowMessage(s + IntToStr(i));
end;
以及以下两个过程:
procedure CallObjMethWorking(AMethod: TMethod; const AStrValue: string; const AIntValue: Integer);
begin
asm
PUSH DWORD PTR AIntValue;
PUSH DWORD PTR AStrValue;
CALL AMethod.Code;
end;
end;
procedure CallObjMethNOTWorking(AInstance, ACode: Pointer; const AStrValue: string; const AIntValue: Integer);
begin
asm
MOV EAX, AInstance;
PUSH DWORD PTR AIntValue;
PUSH DWORD PTR AStrValue;
CALL ACode;
end;
end;
为了测试工作版本,需要调用以下命令:
procedure ...;
var
LObj: TMyObj;
LMethod: TMethod;
LStrVal: string;
LIntVal: Integer;
begin
LObj := TMyObj.Create;
try
LMethod.Data := Pointer( LObj );
LMethod.Code := LObj.MethodAddress('testex');
LStrVal := 'The year is:' + sLineBreak;
LIntVal := 2012;
CallObjMethWorking(LMethod, LStrVal, LIntVal);
finally
LObj.Free;
end; // tryf
end;
为了测试不工作版本:
procedure ...;
var
LObj: TMyObj;
LCode: Pointer;
LData: Pointer;
LStrVal: string;
LIntVal: Integer;
begin
LObj := TMyObj.Create;
try
LData := Pointer( LObj );
LCode := LObj.MethodAddress('testex');
LStrVal := 'The year is:' + sLineBreak;
LIntVal := 2012;
CallObjMethNOTWorking(LData, LCode, LStrVal, LIntVal);
finally
LObj.Free;
end; // tryf
end;
最后一个问题:为什么 CallObjMethNOTWorking 不工作,而 CallObjMethWorking 工作?我猜测编译器对待 TMethod 的方式有些特殊...但由于我的汇编知识有限,我无法理解它。
如果有人能向我解释一下,我将不胜感激,谢谢!
最佳答案
Henrick Hellström 的 answer 是正确的,我注意到您的问题被标记为 Delphi 2010,因此仅涉及 Win32。但是,您可能有兴趣了解如果继续使用 Win64 (Delphi >= XE2),情况会是什么样子,因此我在 Henrick 的代码中添加了一个示例 Win64 版本:
procedure CallObjMeth(AInstance, ACode: Pointer; const AStrValue: string; const AIntValue: Integer); stdcall;
asm
{$IFDEF CPU386}
MOV EAX, AInstance;
MOV EDX, DWORD PTR AStrValue;
MOV ECX, DWORD PTR AIntValue;
{$IFDEF MACOS}
//On MacOSX32 ESP = #######Ch here
SUB ESP, 0Ch
{$ENDIF}
CALL ACode;
{$IFDEF MACOS}
ADD ESP, 0Ch // restoring stack
{$ENDIF}
{$ENDIF}
{$IFDEF CPUX64}{$IFDEF WIN64} // <- see comments
.NOFRAME //Disable stack frame generation
//MOV RCX, AInstance {RCX} //<- not necessary because AInstance already is in RCX
MOV R10, ACode {RDX}
MOV RDX, AStrValue {R8}
MOV R8D, AIntValue {R9D}
SUB RSP, 28h //Set up stack shadow space and align stack: 4*8 bytes for 4 params + 8 bytes bytes for alignment
{$IFNDEF DO_NOT_TEST_STACK_ALIGNMENT}
MOVDQA XMM5, [RSP] //Ensure that RSP is aligned to DQWORD boundary -> exception otherwise
{$ENDIF}
CALL R10 //ACode
ADD RSP, 28h //Restore stack
{$ENDIF}{$ENDIF}
end;
需要做一些解释性说明:
1) ASM
语句:在 Delphi XE2 x64 中,没有混合使用 pascal 和 asm 代码,因此编写汇编代码的唯一方法是在一个例程中由单个 asm..end
block 组成,没有 begin..end
。请注意,32 位 asm 代码周围的 begin..end
也确实有影响。具体来说,您强制生成堆栈帧并让编译器制作函数参数的本地副本。 (如果您首先使用汇编,您可能不希望编译器这样做。)
2) 调用约定:在 Win64 上,只有一个调用约定。像 register
和 stdcall
这样的东西实际上是没有意义的;都是一样的,Microsoft's Win64 calling convention 。本质上是这样的:参数在RCX
、RDX
、R8
和R9
寄存器中传递(和/或XMM0-XMM4
,返回RAX/XMM0
中的值。大于64位的值通过引用传递。
被调用的函数可以使用:RAX、RCX、RDX、R8-R11、ST(0)-ST(7)、XMM0-XMM5、YMM0-YMM5、YMM6H-YMM15H
,并且必须保留RBX、RSI、RDI、RBP、R12-R15、XMM6-XMM15
。在适当的情况下,被调用的函数需要发出 CLD
/EMMS
/VZEROUPPER
指令将 CPU 恢复到预期状态。
3) 对齐和阴影空间重要的是,每个函数在堆栈上都有自己的影子空间,即使没有参数并且无论被调用的函数是否实际接触它,这至少是 4 个 QWORD 参数的堆栈空间。此外,在每个函数调用的位置(在每个 CALL
语句处),RSP
预计为 16 字节对齐(对于 ESP
也是如此)顺便说一句,在 MacOSX32 上)。这通常会导致类似这样的结果:sub rsp, ##;调用$$; add rsp, ##
构造,其中 ## 是要调用函数的 (QWORD) 参数的总和,加上用于对齐 RSP
的可选 8 个字节。请注意,CALL
处的 RSP
对齐会在函数输入时导致 RSP = ###8h
(因为 CALL
code> 将返回地址放入堆栈中),因此假设在您之前没有人弄乱 RSP
,您可以预期它会是这样。
在提供的示例中,SSE2 MOVDQA
指令用于测试 RSP
的对齐情况。 (XMM5
用作目标寄存器,因为它可以自由修改,但不能包含任何函数参数数据)。
4)假设这里的代码假设编译器不会插入代码来更改RSP
。在某些情况下,这可能不正确,因此请小心做出这种假设。
5) 异常处理 Win64 中的异常处理有点复杂,应该由编译器正确完成(上面的示例代码没有这样做)。为了允许编译器执行此操作,理想情况下您的代码应使用新的 BASM 指令/伪指令 .PARAMS
、.PUSHNV
和 .SAVENV
如Allen Bauer here所述。在正确(错误)的情况下,否则可能会发生不好的事情。
关于delphi - 使用 ASM 调用对象方法 - 第 2 部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9454054/
我需要处理来自旧 Mac 时代(旧摩托罗拉 CPU)的文件。字节是大端字节序,所以我有一个函数可以将 Int64 交换为英特尔小端字节序。该函数是 ASM,可在 32 位 CPU 上运行,但不能在 6
1.概述 转载:史上最通俗易懂的ASM教程 一勺思想 We are all in the gutter, but some of us are looking at the stars. (我们都生活
1.概述 转载:ASM 与 Presto 动态代码生成简介 代码生成是很多计算引擎中常用的执行优化技术,比如我们熟悉的 Apache Spark 和 Presto 在表达式等地方就使用到代码生成技术。
我想在 C++ 程序中使用 ASM 调用地址为 774a7fdch 的函数(kernel32.dll 函数) 我正在使用 Visual Studio 2010。 我该怎么做? call 774a7fd
我是否正确转换了它? 原始 VS C++ 版本: _TEB *pTeb = NULL; _asm { mov eax, fs:[0x18];
阅读自howto_add_systemcall "In general, header files for machine architecture independent system calls
在实现无锁数据结构和时序代码时,通常需要抑制编译器的优化。通常人们使用 asm volatile 和 clobber 列表中的 memory 来执行此操作,但有时您只会看到 asm volatile
这个“strcpy”函数的目的是将src的内容复制到dest,结果很好:显示两行“Hello_src”。 #include static inline char * strcpy(char * de
我正在尝试进行一些汇编编码,我从 C 语言调用函数。代码本身运行良好,但我有两个巨大的问题在很长一段时间内无法解决。第一个是语法高亮 - 我安装了两个不同的(当时一个)asm 高亮扩展到 Visual
我正在研究一些类文件分析,并且正在研究使用 ASM 来读取类。在 Javap 中,操作码以及 tagName 和 tagValue 是内联打印的,但在每个 AbstractInsnNode 中,我只看
我正在尝试弄清楚如何将 ASM 中的 DB 变量用于内联 ASM C++ 我有这个 ASM 代码: filename db "C:\imagen.bmp" eti0: mov ah,3dh mov a
这个“strcpy”函数的目的是将src的内容复制到dest,结果很好:显示两行“Hello_src”。 #include static inline char * strcpy(char * de
在 mm/memory.c 中,它包含一个文件: #include tlb.h 是 include/asm-generic/tlb.h或 arch/arm/include/asm/tlb.h ? 最
你好我找到了一个asm代码......它被集成到c++项目中 template T returned; BYTE *tem = buffer; __asm { mov eax, tem
问题:当我运行 @ 命令提示符 >tasm HelloWorld.asm 顺便说一句,我在输入文件名 HelloWorld.asm 时使用 TAB,所以没有错字.我收到这个致命的命令行错误: Turb
尝试通过 eax 从 asm proc 返回一个 long int,后来又尝试通过 dx:ax。两者都不适合我,因为 C printf 打印的数字与所需的 320L 不同。 x.asm: .model
这是 godbolt 生成的代码. 下面是 Visual Studio 在我的 main.asm 文件上生成的相同代码(通过 Project->C/C++->Output Files->Assembl
在构建具有依赖项的 giraph jar 时,我们收到以下警告.. 真的不知道如何解决这些.. 我们已经尝试过了 useProjectArtifact 为 false 和 解压为真 两者似乎都有效 任
我正在使用 gentoo 并尝试编译一个程序来控制并行端口上的位。它的顶部附近有这条线: #include 当我尝试在其上使用 gcc 时,它会产生以下输出: port.c:4:20: error:
(原帖)将 hibernate 依赖项添加到 pom.xml 时显示错误 2011-10-11 10:36:53.710::WARN: failed guiceFilter java.lang.No
我是一名优秀的程序员,十分优秀!