[MC] Add support for encoding CodeView variable definition ranges

CodeView, like most other debug formats, represents the live range of a
variable so that debuggers might print them out.

They use a variety of records to represent how a particular variable
might be available (in a register, in a frame pointer, etc.) along with
a set of ranges where this debug information is relevant.

However, the format only allows us to use ranges which are limited to a
maximum of 0xF000 in size.  This means that we need to split our debug
information into chunks of 0xF000.

Because the layout of code is not known until *very* late, we must use a
new fragment to record the information we need until we can know
*exactly* what the range is.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@259868 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
David Majnemer 2016-02-05 01:55:49 +00:00
parent 419c3d8a2f
commit 7ddc547ea9
16 changed files with 332 additions and 13 deletions

View File

@ -123,6 +123,8 @@ struct LocalVariableAddrGap {
ulittle16_t Range;
};
enum : uint16_t { MaxDefRange = 0xf000 };
// S_DEFRANGE
struct DefRangeSym {
ulittle32_t Program;

View File

@ -191,6 +191,7 @@ private:
MCDwarfCallFrameFragment &DF);
bool relaxCVInlineLineTable(MCAsmLayout &Layout,
MCCVInlineLineTableFragment &DF);
bool relaxCVDefRange(MCAsmLayout &Layout, MCCVDefRangeFragment &DF);
/// finishLayout - Finalize a layout, including fragment lowering.
void finishLayout(MCAsmLayout &Layout);

View File

@ -166,6 +166,13 @@ public:
void encodeInlineLineTable(MCAsmLayout &Layout,
MCCVInlineLineTableFragment &F);
void
emitDefRange(MCObjectStreamer &OS,
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
StringRef FixedSizePortion);
void encodeDefRange(MCAsmLayout &Layout, MCCVDefRangeFragment &F);
/// Emits the string table substream.
void emitStringTable(MCObjectStreamer &OS);

View File

@ -41,6 +41,7 @@ public:
FT_LEB,
FT_SafeSEH,
FT_CVInlineLines,
FT_CVDefRange,
FT_Dummy
};
@ -211,7 +212,8 @@ public:
static bool classof(const MCFragment *F) {
MCFragment::FragmentType Kind = F->getKind();
return Kind == MCFragment::FT_Relaxable || Kind == MCFragment::FT_Data;
return Kind == MCFragment::FT_Relaxable || Kind == MCFragment::FT_Data ||
Kind == MCFragment::FT_CVDefRange;
}
};
@ -509,9 +511,7 @@ public:
: MCFragment(FT_CVInlineLines, false, 0, Sec), SiteFuncId(SiteFuncId),
StartFileId(StartFileId), StartLineNum(StartLineNum),
FnStartSym(FnStartSym), FnEndSym(FnEndSym),
SecondaryFuncs(SecondaryFuncs.begin(), SecondaryFuncs.end()) {
Contents.push_back(0);
}
SecondaryFuncs(SecondaryFuncs.begin(), SecondaryFuncs.end()) {}
/// \name Accessors
/// @{
@ -529,6 +529,37 @@ public:
}
};
/// Fragment representing the .cv_def_range directive.
class MCCVDefRangeFragment : public MCEncodedFragmentWithFixups<32, 4> {
SmallVector<std::pair<const MCSymbol *, const MCSymbol *>, 2> Ranges;
SmallString<32> FixedSizePortion;
/// CodeViewContext has the real knowledge about this format, so let it access
/// our members.
friend class CodeViewContext;
public:
MCCVDefRangeFragment(
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
StringRef FixedSizePortion, MCSection *Sec = nullptr)
: MCEncodedFragmentWithFixups<32, 4>(FT_CVDefRange, false, Sec),
Ranges(Ranges.begin(), Ranges.end()),
FixedSizePortion(FixedSizePortion) {}
/// \name Accessors
/// @{
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> getRanges() const {
return Ranges;
}
StringRef getFixedSizePortion() const { return FixedSizePortion; }
/// @}
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_CVDefRange;
}
};
} // end namespace llvm
#endif

View File

@ -131,6 +131,9 @@ public:
unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
ArrayRef<unsigned> SecondaryFunctionIds) override;
void EmitCVDefRangeDirective(
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
StringRef FixedSizePortion) override;
void EmitCVStringTableDirective() override;
void EmitCVFileChecksumsDirective() override;
void EmitGPRel32Value(const MCExpr *Value) override;

View File

@ -662,6 +662,12 @@ public:
const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
ArrayRef<unsigned> SecondaryFunctionIds);
/// \brief This implements the CodeView '.cv_def_range' assembler
/// directive.
virtual void EmitCVDefRangeDirective(
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
StringRef FixedSizePortion);
/// \brief This implements the CodeView '.cv_stringtable' assembler directive.
virtual void EmitCVStringTableDirective() {}

View File

@ -209,6 +209,9 @@ public:
unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
ArrayRef<unsigned> SecondaryFunctionIds) override;
void EmitCVDefRangeDirective(
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
StringRef FixedSizePortion) override;
void EmitCVStringTableDirective() override;
void EmitCVFileChecksumsDirective() override;
@ -1038,6 +1041,22 @@ void MCAsmStreamer::EmitCVInlineLinetableDirective(
SecondaryFunctionIds);
}
void MCAsmStreamer::EmitCVDefRangeDirective(
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
StringRef FixedSizePortion) {
OS << "\t.cv_def_range\t";
for (std::pair<const MCSymbol *, const MCSymbol *> Range : Ranges) {
OS << ' ';
Range.first->print(OS, MAI);
OS << ' ';
Range.second->print(OS, MAI);
}
OS << ", ";
PrintQuotedString(FixedSizePortion, OS);
EmitEOL();
this->MCStreamer::EmitCVDefRangeDirective(Ranges, FixedSizePortion);
}
void MCAsmStreamer::EmitCVStringTableDirective() {
OS << "\t.cv_stringtable";
EmitEOL();

View File

@ -303,6 +303,8 @@ uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout,
return cast<MCDwarfCallFrameFragment>(F).getContents().size();
case MCFragment::FT_CVInlineLines:
return cast<MCCVInlineLineTableFragment>(F).getContents().size();
case MCFragment::FT_CVDefRange:
return cast<MCCVDefRangeFragment>(F).getContents().size();
case MCFragment::FT_Dummy:
llvm_unreachable("Should not have been added");
}
@ -545,6 +547,11 @@ static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout,
OW->writeBytes(OF.getContents());
break;
}
case MCFragment::FT_CVDefRange: {
const auto &DRF = cast<MCCVDefRangeFragment>(F);
OW->writeBytes(DRF.getContents());
break;
}
case MCFragment::FT_Dummy:
llvm_unreachable("Should not have been added");
}
@ -673,19 +680,24 @@ void MCAssembler::layout(MCAsmLayout &Layout) {
// Evaluate and apply the fixups, generating relocation entries as necessary.
for (MCSection &Sec : *this) {
for (MCFragment &Frag : Sec) {
MCEncodedFragment *F = dyn_cast<MCEncodedFragment>(&Frag);
// Data and relaxable fragments both have fixups. So only process
// those here.
// FIXME: Is there a better way to do this? MCEncodedFragmentWithFixups
// being templated makes this tricky.
if (!F || isa<MCCompactEncodedInstFragment>(F))
if (isa<MCEncodedFragment>(&Frag) &&
isa<MCCompactEncodedInstFragment>(&Frag))
continue;
if (!isa<MCEncodedFragment>(&Frag) && !isa<MCCVDefRangeFragment>(&Frag))
continue;
ArrayRef<MCFixup> Fixups;
MutableArrayRef<char> Contents;
if (auto *FragWithFixups = dyn_cast<MCDataFragment>(F)) {
if (auto *FragWithFixups = dyn_cast<MCDataFragment>(&Frag)) {
Fixups = FragWithFixups->getFixups();
Contents = FragWithFixups->getContents();
} else if (auto *FragWithFixups = dyn_cast<MCRelaxableFragment>(F)) {
} else if (auto *FragWithFixups = dyn_cast<MCRelaxableFragment>(&Frag)) {
Fixups = FragWithFixups->getFixups();
Contents = FragWithFixups->getContents();
} else if (auto *FragWithFixups = dyn_cast<MCCVDefRangeFragment>(&Frag)) {
Fixups = FragWithFixups->getFixups();
Contents = FragWithFixups->getContents();
} else
@ -693,7 +705,7 @@ void MCAssembler::layout(MCAsmLayout &Layout) {
for (const MCFixup &Fixup : Fixups) {
uint64_t FixedValue;
bool IsPCRel;
std::tie(FixedValue, IsPCRel) = handleFixup(Layout, *F, Fixup);
std::tie(FixedValue, IsPCRel) = handleFixup(Layout, Frag, Fixup);
getBackend().applyFixup(Fixup, Contents.data(),
Contents.size(), FixedValue, IsPCRel);
}
@ -828,6 +840,13 @@ bool MCAssembler::relaxCVInlineLineTable(MCAsmLayout &Layout,
return OldSize != F.getContents().size();
}
bool MCAssembler::relaxCVDefRange(MCAsmLayout &Layout,
MCCVDefRangeFragment &F) {
unsigned OldSize = F.getContents().size();
getContext().getCVContext().encodeDefRange(Layout, F);
return OldSize != F.getContents().size();
}
bool MCAssembler::layoutSectionOnce(MCAsmLayout &Layout, MCSection &Sec) {
// Holds the first fragment which needed relaxing during this layout. It will
// remain NULL if none were relaxed.
@ -863,6 +882,9 @@ bool MCAssembler::layoutSectionOnce(MCAsmLayout &Layout, MCSection &Sec) {
RelaxedFrag =
relaxCVInlineLineTable(Layout, *cast<MCCVInlineLineTableFragment>(I));
break;
case MCFragment::FT_CVDefRange:
RelaxedFrag = relaxCVDefRange(Layout, *cast<MCCVDefRangeFragment>(I));
break;
}
if (RelaxedFrag && !FirstRelaxedFragment)
FirstRelaxedFragment = &*I;

View File

@ -19,6 +19,7 @@
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCObjectStreamer.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/COFF.h"
using namespace llvm;
@ -236,6 +237,16 @@ void CodeViewContext::emitInlineLineTableForFunction(
SecondaryFunctionIds, OS.getCurrentSectionOnly());
}
void CodeViewContext::emitDefRange(
MCObjectStreamer &OS,
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
StringRef FixedSizePortion) {
// Create and insert a fragment into the current section that will be encoded
// later.
new MCCVDefRangeFragment(Ranges, FixedSizePortion,
OS.getCurrentSectionOnly());
}
static unsigned computeLabelDiff(MCAsmLayout &Layout, const MCSymbol *Begin,
const MCSymbol *End) {
MCContext &Ctx = Layout.getAssembler().getContext();
@ -352,6 +363,58 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout,
compressAnnotation(std::min(EndSymLength, LocAfterLength), Buffer);
}
void CodeViewContext::encodeDefRange(MCAsmLayout &Layout,
MCCVDefRangeFragment &Frag) {
MCContext &Ctx = Layout.getAssembler().getContext();
SmallVectorImpl<char> &Contents = Frag.getContents();
Contents.clear();
SmallVectorImpl<MCFixup> &Fixups = Frag.getFixups();
Fixups.clear();
raw_svector_ostream OS(Contents);
// Write down each range where the variable is defined.
for (std::pair<const MCSymbol *, const MCSymbol *> Range : Frag.getRanges()) {
unsigned RangeSize = computeLabelDiff(Layout, Range.first, Range.second);
unsigned Bias = 0;
// We must split the range into chunks of MaxDefRange, this is a fundamental
// limitation of the file format.
do {
uint16_t Chunk = std::min((uint32_t)MaxDefRange, RangeSize);
const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Range.first, Ctx);
const MCBinaryExpr *BE =
MCBinaryExpr::createAdd(SRE, MCConstantExpr::create(Bias, Ctx), Ctx);
MCValue Res;
BE->evaluateAsRelocatable(Res, &Layout, /*Fixup=*/nullptr);
// Each record begins with a 2-byte number indicating how large the record
// is.
StringRef FixedSizePortion = Frag.getFixedSizePortion();
// Our record is a fixed sized prefix and a LocalVariableAddrRange that we
// are artificially constructing.
size_t RecordSize =
FixedSizePortion.size() + sizeof(LocalVariableAddrRange);
// Write out the recrod size.
support::endian::Writer<support::little>(OS).write<uint16_t>(RecordSize);
// Write out the fixed size prefix.
OS << FixedSizePortion;
// Make space for a fixup that will eventually have a section relative
// relocation pointing at the offset where the variable becomes live.
Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_4));
Contents.resize(Contents.size() + 4); // Fixup for code start.
// Make space for a fixup that will record the section index for the code.
Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_2));
Contents.resize(Contents.size() + 2); // Fixup for section index.
// Write down the range's extent.
support::endian::Writer<support::little>(OS).write<uint16_t>(Chunk);
// Move on to the next range.
Bias += Chunk;
RangeSize -= Chunk;
} while (RangeSize > 0);
}
}
//
// This is called when an instruction is assembled into the specified section
// and if there is information from the last .cv_loc directive that has yet to have

View File

@ -292,6 +292,9 @@ void MCFragment::destroy() {
case FT_CVInlineLines:
delete cast<MCCVInlineLineTableFragment>(this);
return;
case FT_CVDefRange:
delete cast<MCCVDefRangeFragment>(this);
return;
case FT_Dummy:
delete cast<MCDummyFragment>(this);
return;
@ -331,6 +334,7 @@ LLVM_DUMP_METHOD void MCFragment::dump() {
case MCFragment::FT_LEB: OS << "MCLEBFragment"; break;
case MCFragment::FT_SafeSEH: OS << "MCSafeSEHFragment"; break;
case MCFragment::FT_CVInlineLines: OS << "MCCVInlineLineTableFragment"; break;
case MCFragment::FT_CVDefRange: OS << "MCCVDefRangeTableFragment"; break;
case MCFragment::FT_Dummy: OS << "MCDummyFragment"; break;
}
@ -435,6 +439,16 @@ LLVM_DUMP_METHOD void MCFragment::dump() {
OS << " Sym:" << *F->getFnStartSym();
break;
}
case MCFragment::FT_CVDefRange: {
const auto *F = cast<MCCVDefRangeFragment>(this);
OS << "\n ";
for (std::pair<const MCSymbol *, const MCSymbol *> RangeStartEnd :
F->getRanges()) {
OS << " RangeStart:" << RangeStartEnd.first;
OS << " RangeEnd:" << RangeStartEnd.second;
}
break;
}
case MCFragment::FT_Dummy:
break;
}

View File

@ -396,6 +396,13 @@ void MCObjectStreamer::EmitCVInlineLinetableDirective(
SecondaryFunctionIds);
}
void MCObjectStreamer::EmitCVDefRangeDirective(
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
StringRef FixedSizePortion) {
getContext().getCVContext().emitDefRange(*this, Ranges, FixedSizePortion);
this->MCStreamer::EmitCVDefRangeDirective(Ranges, FixedSizePortion);
}
void MCObjectStreamer::EmitCVStringTableDirective() {
getContext().getCVContext().emitStringTable(*this);
}

View File

@ -358,7 +358,7 @@ private:
DK_IFNOTDEF, DK_ELSEIF, DK_ELSE, DK_ENDIF,
DK_SPACE, DK_SKIP, DK_FILE, DK_LINE, DK_LOC, DK_STABS,
DK_CV_FILE, DK_CV_LOC, DK_CV_LINETABLE, DK_CV_INLINE_LINETABLE,
DK_CV_STRINGTABLE, DK_CV_FILECHECKSUMS,
DK_CV_DEF_RANGE, DK_CV_STRINGTABLE, DK_CV_FILECHECKSUMS,
DK_CFI_SECTIONS, DK_CFI_STARTPROC, DK_CFI_ENDPROC, DK_CFI_DEF_CFA,
DK_CFI_DEF_CFA_OFFSET, DK_CFI_ADJUST_CFA_OFFSET, DK_CFI_DEF_CFA_REGISTER,
DK_CFI_OFFSET, DK_CFI_REL_OFFSET, DK_CFI_PERSONALITY, DK_CFI_LSDA,
@ -396,11 +396,13 @@ private:
bool parseDirectiveLoc();
bool parseDirectiveStabs();
// ".cv_file", ".cv_loc", ".cv_linetable", "cv_inline_linetable"
// ".cv_file", ".cv_loc", ".cv_linetable", "cv_inline_linetable",
// ".cv_def_range"
bool parseDirectiveCVFile();
bool parseDirectiveCVLoc();
bool parseDirectiveCVLinetable();
bool parseDirectiveCVInlineLinetable();
bool parseDirectiveCVDefRange();
bool parseDirectiveCVStringTable();
bool parseDirectiveCVFileChecksums();
@ -1656,6 +1658,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
return parseDirectiveCVLinetable();
case DK_CV_INLINE_LINETABLE:
return parseDirectiveCVInlineLinetable();
case DK_CV_DEF_RANGE:
return parseDirectiveCVDefRange();
case DK_CV_STRINGTABLE:
return parseDirectiveCVStringTable();
case DK_CV_FILECHECKSUMS:
@ -3286,6 +3290,40 @@ bool AsmParser::parseDirectiveCVInlineLinetable() {
return false;
}
/// parseDirectiveCVDefRange
/// ::= .cv_def_range RangeStart RangeEnd (GapStart GapEnd)*, bytes*
bool AsmParser::parseDirectiveCVDefRange() {
SMLoc Loc;
std::vector<std::pair<const MCSymbol *, const MCSymbol *>> Ranges;
while (getLexer().is(AsmToken::Identifier)) {
Loc = getLexer().getLoc();
StringRef GapStartName;
if (parseIdentifier(GapStartName))
return Error(Loc, "expected identifier in directive");
MCSymbol *GapStartSym = getContext().getOrCreateSymbol(GapStartName);
Loc = getLexer().getLoc();
StringRef GapEndName;
if (parseIdentifier(GapEndName))
return Error(Loc, "expected identifier in directive");
MCSymbol *GapEndSym = getContext().getOrCreateSymbol(GapEndName);
Ranges.push_back({GapStartSym, GapEndSym});
}
if (getLexer().isNot(AsmToken::Comma))
return TokError("unexpected token in directive");
Lex();
std::string FixedSizePortion;
if (parseEscapedString(FixedSizePortion))
return true;
Lex();
getStreamer().EmitCVDefRangeDirective(Ranges, FixedSizePortion);
return false;
}
/// parseDirectiveCVStringTable
/// ::= .cv_stringtable
bool AsmParser::parseDirectiveCVStringTable() {
@ -4615,6 +4653,7 @@ void AsmParser::initializeDirectiveKindMap() {
DirectiveKindMap[".cv_loc"] = DK_CV_LOC;
DirectiveKindMap[".cv_linetable"] = DK_CV_LINETABLE;
DirectiveKindMap[".cv_inline_linetable"] = DK_CV_INLINE_LINETABLE;
DirectiveKindMap[".cv_def_range"] = DK_CV_DEF_RANGE;
DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE;
DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS;
DirectiveKindMap[".sleb128"] = DK_SLEB128;

View File

@ -201,6 +201,10 @@ void MCStreamer::EmitCVInlineLinetableDirective(
const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
ArrayRef<unsigned> SecondaryFunctionIds) {}
void MCStreamer::EmitCVDefRangeDirective(
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
StringRef FixedSizePortion) {}
void MCStreamer::EmitEHSymAttributes(const MCSymbol *Symbol,
MCSymbol *EHSymbol) {
}

View File

@ -785,6 +785,10 @@ void WinCOFFObjectWriter::recordRelocation(
}
}
// The fixed value never makes sense for section indicies, ignore it.
if (Fixup.getKind() == FK_SecRel_2)
FixedValue = 0;
if (TargetObjectWriter->recordRelocation(Fixup))
coff_section->Relocations.push_back(Reloc);
}

View File

@ -0,0 +1,97 @@
# RUN: llvm-mc -triple=i686-pc-win32 -filetype=obj < %s | llvm-readobj -codeview -codeview-subsection-bytes | FileCheck %s
.text
.def @feat.00;
.scl 3;
.type 0;
.endef
.globl @feat.00
@feat.00 = 1
.def _g;
.scl 2;
.type 32;
.endef
.globl _g
.p2align 4, 0x90
_g: # @g
Lfunc_begin0:
.cv_file 1 "\\usr\\local\\google\\home\\majnemer\\llvm\\src\\<stdin>"
.cv_loc 0 1 3 0 is_stmt 0 # <stdin>:3:0
# BB#0: # %entry
pushl %ebp
movl %esp, %ebp
subl $8, %esp
leal -4(%ebp), %eax
Lvar_begin0:
#DEBUG_VALUE: g:x <- %EAX
.cv_loc 0 1 4 7 # <stdin>:4:7
movl $0, -4(%ebp)
.cv_loc 0 1 5 3 # <stdin>:5:3
movl %eax, (%esp)
calll _f
.cv_loc 0 1 6 1 # <stdin>:6:1
Lvar_end0:
addl $8, %esp
popl %ebp
retl
Lfunc_end0:
.section .debug$T,"dr"
.long 4 # Debug section magic
.short 6 # Type record length
.short 4609 # Leaf type: LF_ARGLIST
.long 0 # Number of arguments
.short 14 # Type record length
.short 4104 # Leaf type: LF_PROCEDURE
.long 3 # Return type index
.byte 0 # Calling convention
.byte 0 # Function options
.short 0 # # of parameters
.long 4096 # Argument list type index
.short 12 # Type record length
.short 5633 # Leaf type: LF_FUNC_ID
.long 0 # Scope type index
.long 4097 # Function type
.asciz "g" # Function name
.section .debug$S,"dr"
.long 4 # Debug section magic
.long 241 # Symbol subsection for g
.long Ltmp1-Ltmp0 # Subsection size
Ltmp0:
.short Ltmp3-Ltmp2 # Record length
Ltmp2:
.short 4423 # Record kind: S_GPROC32_ID
.long 0 # PtrParent
.long 0 # PtrEnd
.long 0 # PtrNext
.long Lfunc_end0-_g # Code size
.long 0 # Offset after prologue
.long 0 # Offset before epilogue
.long 0 # Function type index
.secrel32 _g # Function section relative address
.secidx _g # Function section index
.byte 0 # Flags
.asciz "g" # Function name
Ltmp3:
.short 2 # Record length
.short 4431 # Record kind: S_PROC_ID_END
.cv_def_range Lvar_begin0 Lvar_end0, "\102\021\374\377\377\377"
# CHECK: DefRangeFramePointerRel {
# CHECK: Offset: -4
# CHECK: LocalVariableAddrRange {
# CHECK: OffsetStart: .text+0x9
# CHECK: ISectStart: 0x0
# CHECK: Range: 15
# CHECK: }
# CHECK: }
# CHECK: BlockRelocations [
# CHECK: 0x4 IMAGE_REL_I386_SECREL .text
# CHECK: 0x8 IMAGE_REL_I386_SECTION .text
# CHECK: ]
Ltmp1:
.p2align 2
.cv_linetable 0, _g, Lfunc_end0
.cv_filechecksums # File index to string table offset subsection
.cv_stringtable # String table

View File

@ -20,7 +20,7 @@ foo:
.reloc 16, dir32, foo@imgrel # ASM: .reloc 16, dir32, foo@IMGREL
# OBJ-32-LABEL: Name: .text
# OBJ-32: 0000: 04000000 00000000 08000000
# OBJ-32: 0000: 04000000 00000000 00000000
# OBJ-32-LABEL: }
# OBJ-32-LABEL: Relocations [
# OBJ-32: 0x4 IMAGE_REL_I386_DIR32 foo
@ -30,7 +30,7 @@ foo:
# OBJ-32: 0x10 IMAGE_REL_I386_DIR32NB foo
# OBJ-64-LABEL: Name: .text
# OBJ-64: 0000: 04000000 00000000 08000000
# OBJ-64: 0000: 04000000 00000000 00000000
# OBJ-64-LABEL: }
# OBJ-64-LABEL: Relocations [
# OBJ-64: 0x4 IMAGE_REL_AMD64_ADDR32 foo