Как я могу получить адрес внутренних функций System.pas?

Я работаю над компилятором JIT и пытаюсь понять, как выводить правильные блоки очистки для управляемых типов, таких как строки.

Разборка блока очистки для функции, имеющей одну локальную переменную типа string, выглядит так:

0044333C 648910           mov fs:[eax],edx
0044333F 6854334400       push $00443354
00443344 8D45FC           lea eax,[ebp-$04]
00443347 E81834FCFF       call @UStrClr
0044334C C3               ret 
0044334D E9062BFCFF       jmp @HandleFinally
00443352 EBF0             jmp $00443344

К сожалению, у меня нет хорошего способа получить адреса @UStrClr и @HandleFinally, чтобы мой JITter мог их вставить. Они объявлены в System.Pas как _UStrClr и _HandleFinally в разделе interface, но, очевидно, происходит некое «волшебство», потому что попытка использовать эти идентификаторы приводит к ошибке компилятора.

Поэтому я попробовал подпрограмму ASM, где я объявил глобальный указатель и сказал mov func_ustr_clear, @UStrClear. На этот раз я не получаю ошибку необъявленного идентификатора; Я получаю нечто еще более странное:

[DCC Error]: E2107 Operand size mismatch

Так кто-нибудь знает, как это сделать правильно?


person Mason Wheeler    schedule 20.01.2014    source источник
comment
Может быть, вызов Finalize - это вариант?   -  person Remko    schedule 20.01.2014
comment
Если у вас есть madExcept, его исходный код — кладезь подобных техник.   -  person David Heffernan    schedule 20.01.2014


Ответы (1)


Попробуйте эти функции, чтобы получить адрес UStrClr и HandleFinally:

function GetUStrClrAddress: Pointer;
asm
{$IFDEF CPUX64}
  mov rcx, offset System.@UStrClr;
  mov @Result, rcx;
{$ELSE}
  mov @Result, offset System.@UStrClr;
{$ENDIF}
end;

function GetHandleFinallyAddress: Pointer;
asm
{$IFDEF CPUX64}
  mov rcx, offset System.@HandleFinally;
  mov @Result, rcx;
{$ELSE}
  mov @Result, offset System.@HandleFinally;
{$ENDIF}
end;

Редактировать:

@ArnaudBouchez также предлагает дальнейшую оптимизацию. Непосредственно помещая значение в регистр возврата функции, функция работает немного быстрее.

function GetUStrClrAddress: Pointer; 
asm 
  {$ifdef CPU64} 
    mov rax,offset System.@UStrClr 
  {$else} 
    mov eax,offset System.@UStrClr 
  {$endif} 
end;

Дополнительную информацию об использовании ассемблера в Delphi можно найти здесь (и использование ключевого слова OFFSET), Assembly Expressions, Expression Classes.

person LU RD    schedule 20.01.2014
comment
@Result здесь можно заменить на Result, насколько я знаю. Или напрямую зарегистрируйте результат, но Delphi asm сделает это за вас, так что Result здесь вполне подойдет. +1 - person Arnaud Bouchez; 20.01.2014
comment
Альтернативный более короткий/чистый код: function GetUStrClrAddress: Pointer; asm {$ifdef CPU64} mov rax,offset System.@UStrClr {$else} mov eax,offset System.@UStrClr {$endif} end; - person Arnaud Bouchez; 20.01.2014
comment
Ага! Ключевое слово Offset было тем, чего мне не хватало. Спасибо! - person Mason Wheeler; 20.01.2014
comment
Мне интересно: будет ли этого по-прежнему достаточно для 32-битного позиционно-независимого кода (PIC), или вам придется добавить адрес GOT (обычно в EBX) - это, очевидно, не проблема для Win32 (и я не не знаю, заботятся ли ОП о других ОС). - person PhiS; 20.01.2014
comment
@PhiS, извините, у меня нет опыта использования ОС PIC, таких как OSX или Linux. - person LU RD; 20.01.2014
comment
Я думаю, код PIC @PhiS будет выглядеть так: MOV EAX,[EBX].OFFSET System.@UStrClr - person David Heffernan; 20.01.2014