什么是TTypeInfo之前的"身份指针"?

Mas*_*ler 8 delphi pointers internals rtti

如果你在Delphi内部进行足够的搜索,你会发现一些奇怪的东西,并且显然没有记录编译器生成的TTypeInfo记录.如果PTypeInfo指向地址X处的TTypeInfo记录,X - 4那么您将发现接下来的4个字节描述了指向X的指针.例如:

procedure test(info: PTypeInfo);
var
  addr: cardinal;
  ptr: PPointer;
begin
  addr := cardinal(info);
  writeln('addr: ', addr);
  dec(addr, 4);
  ptr := PPointer(addr);
  addr := cardinal(ptr^);
  writeln('addr: ', addr);
end;
Run Code Online (Sandbox Code Playgroud)

将编译器生成的任何合法的PTypeInfo传递给此例程,并且它将输出相同的地址两次.我在TypInfo.pas中略微探讨了一下,但是我没有看到任何提到这个"身份指针"的东西或它的用途.有谁知道为什么会这样?对于从至少D3到D2010的每个版本的Delphi,这似乎都是正确的.

Bar*_*lly 11

它非常简单:包和动态链接.

BPL是DLL.DLL通过修补的表进行链接,而不是EXE或DLL中的所有代码链接到正在修补的DLL(这会对在多个进程之间共享只读内存造成很大的危害).为了防止需要引用TypeInfo(SomeType)代码中的某个地方,或EXE或DLL的typeinfo,在链接到BPL时被修改,而是通过导入表进行间接寻址.

在此程序中,静态链接与BPL链接时很容易看出差异:

{$apptype console}
uses TypInfo, SysUtils;
type
  TFoo = class(TObject);
var
  x: PPTypeInfo;
begin
  x := GetTypeData(TypeInfo(TFoo))^.ParentInfo;
  Writeln(x^^.Name);
  Writeln(Format('x  %p', [x]));
  Writeln(Format('x^ %p', [x^]));
end.
Run Code Online (Sandbox Code Playgroud)

在我的本地机器上编译dcc32 test.pas,它输出:

TObject
x  00401B64
x^ 00401B68
Run Code Online (Sandbox Code Playgroud)

但是当使用RTL包编译时dcc32 -LUrtl test.pas,它会输出:

TObject
x  004051F0
x^ 40001DA4
Run Code Online (Sandbox Code Playgroud)

希望这可以解决它.

  • @Mason所有typeinfo fixups - 从一个typeinfo到另一个blob的指针 - 是PPTypeInfo类型,而不是PTypeInfo,用于处理动态链接情况.在静态链接的情况下,需要有一个中间指针使约定起作用,而typeinfo本身的一部分与任何一个一样有意义.也就是说,它不适用于链接器; 它是因为惯例而存在,并且由于动态链接的原因,因为它是最大化页面共享潜力的方式. (2认同)