gpt4 book ai didi

delphi - 重写Delphi函数System.Round

转载 作者:行者123 更新时间:2023-12-03 14:45:09 24 4
gpt4 key购买 nike

我刚刚发现我必须重新实现的软件广泛使用 System.Round()。问题是该函数使用“银行舍入”,并且不能像 Math.RoundTo() (rmDown、rmUp、rmNearest、rmTruncate) 那样更改行为。

我必须将行为更改为“正常舍入”(12.5 -> 13 而不是 12.5 -> 12)...所以我想全局覆盖 System.Round() 。我想这样做,因为 Round() 使用了很多次,我不想手动更改它们。

这怎么可能?

最佳答案

警告:虽然下面的答案解决了提出的问题,但我建议没有人使用它。如果您想以不同于 Round 的方式执行舍入,请编写并调用专用函数。

<小时/>

您可以使用运行时代码 Hook 来更改 Round 的实现。

问题在于,获取 Round 函数的地址有点棘手,因为它是一个内在函数。您还必须小心遵循所使用的调用约定。输入值在 x87 堆栈寄存器 ST(0) 中传递,返回值是 EDX:EAX 中的 64 位整数。

具体操作方法如下。

procedure PatchCode(Address: Pointer; const NewCode; Size: Integer);
var
OldProtect: DWORD;
begin
if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then
begin
Move(NewCode, Address^, Size);
FlushInstructionCache(GetCurrentProcess, Address, Size);
VirtualProtect(Address, Size, OldProtect, @OldProtect);
end;
end;

type
PInstruction = ^TInstruction;
TInstruction = packed record
Opcode: Byte;
Offset: Integer;
end;

procedure RedirectProcedure(OldAddress, NewAddress: Pointer);
var
NewCode: TInstruction;
begin
NewCode.Opcode := $E9;//jump relative
NewCode.Offset :=
NativeInt(NewAddress)-NativeInt(OldAddress)-SizeOf(NewCode);
PatchCode(OldAddress, NewCode, SizeOf(NewCode));
end;

function System_Round: Pointer;
asm
MOV EAX, offset System.@Round
end;

procedure _ROUND;
asm
{ -> FST(0) Extended argument }
{ <- EDX:EAX Result }

// your implementation goes here
end;

initialization
RedirectProcedure(System_Round, @_ROUND);

如果您更愿意在 Pascal 中而不是 asm 中实现您的版本,那么您需要将 _ROUND 的非标准调用约定调整为标准 Delphi 调用约定。像这样:

function MyRound(x: Extended): Int64;
begin
// your implementation goes here
end;

procedure _ROUND;
var
x: Extended;
asm
{ -> FST(0) Extended argument }
{ <- EDX:EAX Result }

FSTP TBYTE PTR [x]
CALL MyRound
end;

请注意,我在这里假设您的程序面向 32 位。如果您需要面向 64 位,那么原理大致相同,但细节明显不同。

关于delphi - 重写Delphi函数System.Round,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16979435/

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