fix(opdf): export class vtables under --debug-opdf so .opdf links
The OPDF class record stores each class's VMTAddress (the debugger reads an object's VMT pointer at runtime and matches it to identify the dynamic type). The QBE backend emits user-class and generic-instance vtables as LOCAL symbols (`data $vtable_X`), while the .opdf debug section — assembled as a separate object file — references `vtable_X`. A local symbol is not visible across object files, so every `--debug-opdf` build of a program containing a class failed to link with "undefined reference to vtable_X". Add an OPDF-mode flag to the codegen (ICodeGen.SetOpdfMode, wired from the driver's OPDFEnabled). When on, the QBE backend emits user/generic vtables as `export data` so the .opdf object can resolve them; when off (every normal build) the output is byte-for-byte unchanged — verified: non-OPDF IR still emits `data $vtable_TThing`, --debug-opdf emits `export data $vtable_TThing`. The native backend already emits its vtables `.globl`, so its SetOpdfMode is a no-op. Scope is deliberately gated on OPDF mode to avoid duplicate-symbol errors in the separate-compilation (per-unit) path, where the same generic vtable can appear in multiple objects; OPDF is only used with whole-program --source compiles. Result: `--debug-opdf` now links and runs class programs, and the OPDF reference debugger loads them. Full suite OK (2679), FIXPOINT_OK (output unchanged for non-OPDF builds).
This commit is contained in:
parent
d3777ffcfa
commit
971897a411
|
|
@ -941,6 +941,7 @@ begin
|
|||
else
|
||||
CG := TCodeGenQBE.Create();
|
||||
CG.SetDebugMode(DebugMode);
|
||||
CG.SetOpdfMode(OPDFEnabled);
|
||||
if IsUnitMode then
|
||||
begin
|
||||
{ Unit-as-top-level: emit just the unit's bodies, no program wrapping, no @main. }
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ type
|
|||
procedure GenerateUnit(AUnit: TUnit);
|
||||
procedure SetSymbolTable(ASymTable: TSymbolTable);
|
||||
procedure SetDebugMode(AEnabled: Boolean);
|
||||
procedure SetOpdfMode(AEnabled: Boolean);
|
||||
procedure AppendUnit(AUnit: TUnit);
|
||||
procedure AppendProgram(AProg: TProgram);
|
||||
function GetOutput: string;
|
||||
|
|
@ -125,6 +126,13 @@ begin
|
|||
FDebugMode := AEnabled;
|
||||
end;
|
||||
|
||||
procedure TCodeGenNative.SetOpdfMode(AEnabled: Boolean);
|
||||
begin
|
||||
{ No-op: OPDF debug info is not yet wired through the native backend. Its
|
||||
own vtables are already emitted .globl (see EmitClassSection), so there is
|
||||
nothing to toggle here. }
|
||||
end;
|
||||
|
||||
procedure TCodeGenNative.Generate(AProg: TProgram);
|
||||
begin
|
||||
Self.EnsureBackend();
|
||||
|
|
|
|||
|
|
@ -44,6 +44,13 @@ type
|
|||
{ Enable backend debug/leak-tracking behaviour. }
|
||||
procedure SetDebugMode(AEnabled: Boolean);
|
||||
|
||||
{ Enable OPDF-debug code shaping. When on, the backend emits class vtables
|
||||
as exported (global) symbols so the separately-assembled .opdf section can
|
||||
reference them across object files (the OPDF class record stores each
|
||||
class's VMTAddress for runtime dynamic-type resolution). Off by default,
|
||||
so normal builds are byte-for-byte unchanged. }
|
||||
procedure SetOpdfMode(AEnabled: Boolean);
|
||||
|
||||
{ Multi-unit compilation: append unit IR to existing output without
|
||||
resetting the output buffer or string-literal table. }
|
||||
procedure AppendUnit(AUnit: TUnit);
|
||||
|
|
|
|||
|
|
@ -154,6 +154,9 @@ type
|
|||
procedure EmitMainHeader;
|
||||
procedure EmitMainFooter;
|
||||
procedure EmitTypeInfoDefs(AProg: TProgram);
|
||||
{ 'export data ' when OPDF-debug mode is on (so the .opdf section can
|
||||
reference the vtable across object files), else plain 'data '. }
|
||||
function VTableDataPrefix: string;
|
||||
procedure EmitVTableDefs(AProg: TProgram);
|
||||
procedure EmitMethodDefs(AProg: TProgram);
|
||||
procedure EmitInterfaceDefs(AProg: TProgram);
|
||||
|
|
@ -373,6 +376,7 @@ type
|
|||
public
|
||||
FDebugMode: Boolean;
|
||||
FExportAll: Boolean;
|
||||
FOpdfMode: Boolean;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
procedure Generate(AProg: TProgram);
|
||||
|
|
@ -386,6 +390,7 @@ type
|
|||
the units contain class type definitions. Prog.SymbolTable is correct. }
|
||||
procedure SetSymbolTable(ASymTable: TSymbolTable);
|
||||
procedure SetDebugMode(AEnabled: Boolean);
|
||||
procedure SetOpdfMode(AEnabled: Boolean);
|
||||
procedure SetExportAll(AEnabled: Boolean);
|
||||
procedure AppendUnit(AUnit: TUnit);
|
||||
{ Append program IR to existing output (companion to AppendUnit).
|
||||
|
|
@ -6098,8 +6103,11 @@ begin
|
|||
if (TDesc = nil) or not (TDesc is TRecordTypeDesc) then Continue;
|
||||
RT := TRecordTypeDesc(TDesc);
|
||||
if not RT.HasVTable() then Continue;
|
||||
{ TypeInfo pointer is always the first vtable entry }
|
||||
Line := 'data $vtable_' + ClassSymName(TD.Name) +
|
||||
{ TypeInfo pointer is always the first vtable entry. In OPDF-debug mode the
|
||||
vtable is exported so the separately-assembled .opdf section can reference
|
||||
it (the OPDF class record stores each class's VMTAddress); otherwise it
|
||||
stays a local symbol, keeping non-debug output unchanged. }
|
||||
Line := VTableDataPrefix() + '$vtable_' + ClassSymName(TD.Name) +
|
||||
' = { l $typeinfo_' + ClassSymName(TD.Name);
|
||||
for S := 0 to RT.VTableCount() - 1 do
|
||||
begin
|
||||
|
|
@ -6123,7 +6131,7 @@ begin
|
|||
RT := TRecordTypeDesc(GI.TypeDesc);
|
||||
if not RT.HasVTable() then Continue;
|
||||
MName := QBEMangle(GI.TypeName);
|
||||
Line := 'data $vtable_' + MName + ' = { l $typeinfo_' + MName;
|
||||
Line := VTableDataPrefix() + '$vtable_' + MName + ' = { l $typeinfo_' + MName;
|
||||
for S := 0 to RT.VTableCount() - 1 do
|
||||
begin
|
||||
E := RT.VTableEntryAt(S);
|
||||
|
|
@ -11191,6 +11199,19 @@ begin
|
|||
FDebugMode := AEnabled;
|
||||
end;
|
||||
|
||||
procedure TCodeGenQBE.SetOpdfMode(AEnabled: Boolean);
|
||||
begin
|
||||
FOpdfMode := AEnabled;
|
||||
end;
|
||||
|
||||
function TCodeGenQBE.VTableDataPrefix: string;
|
||||
begin
|
||||
if FOpdfMode then
|
||||
Result := 'export data '
|
||||
else
|
||||
Result := 'data ';
|
||||
end;
|
||||
|
||||
procedure TCodeGenQBE.SetExportAll(AEnabled: Boolean);
|
||||
begin
|
||||
FExportAll := AEnabled;
|
||||
|
|
|
|||
Loading…
Reference in a new issue