Delphi экспортирует глобальные переменные из DLL аналогично тому, как экспортирует функции:
library exp;
var
global: Integer;
exports global;
end.
Delphi может импортировать глобальные переменные из DLL, но это немного хакерство: объявите процедуру импорта DLL с тем же именем, что и глобальную для импорта, затем получите адрес процедуры и измените ее соответствующим образом. Импортированные DLL-процедуры, с точки зрения Delphi, являются заглушками, которые выполняют косвенный переход по таблице импорта DLL. Экспортируемые переменные связываются загрузчиком ОС, помещая адрес экспортируемого глобала в таблицу импорта, почти так же, как аналогичным образом исправляются адреса экспортируемых процедур.
Например:
{$apptype console}
procedure global; external 'exp.dll';
function GetGlobalAddr: PInteger;
type
PPPointer = ^PPointer;
var
p: PByte;
begin
p := @global;
Assert(p^ = $FF); // $FF $25 => indirect jump m32
Inc(p);
Assert(p^ = $25);
Inc(p);
Result := PPPointer(p)^^
end;
begin
Writeln(GetGlobalAddr^);
end.
Конечно, последние детали зависят от реализации, платформы и т. Д. Вероятно, более безопасный подход - использовать LoadLibrary
с GetProcAddress
, который будет возвращать адрес глобальной переменной при передаче ее имени. Конечно, это также зависит от платформы.
64-разрядное обновление:
В 64-битной системе Windows код немного отличается. Коды операций одинаковы, но режим адресации для одной и той же последовательности команд отличается; вместо 32-разрядного абсолютного смещения это 32-разрядное относительное смещение.
function GetGlobalAddr: PInteger;
type
PPPointer = ^PPointer;
var
p: PByte;
ofs: Integer;
begin
p := @global;
Assert(p^ = $FF); // $FF $25 => indirect jump m32
Inc(p);
Assert(p^ = $25);
Inc(p);
// 32-bit offset follows
ofs := PInteger(p)^;
// offset is relative to next instruction
Inc(p, SizeOf(ofs) + ofs);
Result := PPPointer(p)^^
end;