Refactor data-in-code annotations.

Use a dedicated MachO load command to annotate data-in-code regions.
This is the same format the linker produces for final executable images,
allowing consistency of representation and use of introspection tools
for both object and executable files.

Data-in-code regions are annotated via ".data_region"/".end_data_region"
directive pairs, with an optional region type.

data_region_directive := ".data_region" { region_type }
region_type := "jt8" | "jt16" | "jt32" | "jta32"
end_data_region_directive := ".end_data_region"

The previous handling of ARM-style "$d.*" labels was broken and has
been removed. Specifically, it didn't handle ARM vs. Thumb mode when
marking the end of the section.

rdar://11459456

llvm-svn: 157062
This commit is contained in:
Jim Grosbach 2012-05-18 19:12:01 +00:00
parent 846e6a6121
commit 4b63d2ae1d
28 changed files with 411 additions and 215 deletions

View File

@ -147,6 +147,11 @@ namespace llvm {
// FIXME: Make this a more general encoding setting?
bool AllowUTF8;
/// UseDataRegionDirectives - This is true if data region markers should
/// be printed as ".data_region/.end_data_region" directives. If false,
/// use "$d/$a" labels instead.
bool UseDataRegionDirectives;
//===--- Data Emission Directives -------------------------------------===//
/// ZeroDirective - this should be set to the directive used to get some
@ -172,18 +177,6 @@ namespace llvm {
const char *Data32bitsDirective; // Defaults to "\t.long\t"
const char *Data64bitsDirective; // Defaults to "\t.quad\t"
/// [Data|Code]Begin - These magic labels are used to marked a region as
/// data or code, and are used to provide additional information for
/// correct disassembly on targets that like to mix data and code within
/// a segment. These labels will be implicitly suffixed by the streamer
/// to give them unique names.
const char *DataBegin; // Defaults to "$d."
const char *CodeBegin; // Defaults to "$a."
const char *JT8Begin; // Defaults to "$a."
const char *JT16Begin; // Defaults to "$a."
const char *JT32Begin; // Defaults to "$a."
bool SupportsDataRegions;
/// GPRel64Directive - if non-null, a directive that is used to emit a word
/// which should be relocated as a 64-bit GP-relative offset, e.g. .gpdword
/// on Mips.
@ -384,14 +377,6 @@ namespace llvm {
const char *getGPRel64Directive() const { return GPRel64Directive; }
const char *getGPRel32Directive() const { return GPRel32Directive; }
/// [Code|Data]Begin label name accessors.
const char *getCodeBeginLabelName() const { return CodeBegin; }
const char *getDataBeginLabelName() const { return DataBegin; }
const char *getJumpTable8BeginLabelName() const { return JT8Begin; }
const char *getJumpTable16BeginLabelName() const { return JT16Begin; }
const char *getJumpTable32BeginLabelName() const { return JT32Begin; }
bool getSupportsDataRegions() const { return SupportsDataRegions; }
/// getNonexecutableStackSection - Targets can implement this method to
/// specify a section to switch to if the translation unit doesn't have any
/// trampolines that require an executable stack.
@ -488,6 +473,9 @@ namespace llvm {
bool doesAllowUTF8() const {
return AllowUTF8;
}
bool doesSupportDataRegionDirectives() const {
return UseDataRegionDirectives;
}
const char *getZeroDirective() const {
return ZeroDirective;
}

View File

@ -651,6 +651,16 @@ struct IndirectSymbolData {
MCSectionData *SectionData;
};
// FIXME: Ditto this. Purely so the Streamer and the ObjectWriter can talk
// to one another.
struct DataRegionData {
// This enum should be kept in sync w/ the mach-o definition in
// llvm/Object/MachOFormat.h.
enum KindTy { Data = 1, JumpTable8, JumpTable16, JumpTable32 } Kind;
MCSymbol *Start;
MCSymbol *End;
};
class MCAssembler {
friend class MCAsmLayout;
@ -668,6 +678,10 @@ public:
const_indirect_symbol_iterator;
typedef std::vector<IndirectSymbolData>::iterator indirect_symbol_iterator;
typedef std::vector<DataRegionData>::const_iterator
const_data_region_iterator;
typedef std::vector<DataRegionData>::iterator data_region_iterator;
private:
MCAssembler(const MCAssembler&); // DO NOT IMPLEMENT
void operator=(const MCAssembler&); // DO NOT IMPLEMENT
@ -698,6 +712,7 @@ private:
std::vector<IndirectSymbolData> IndirectSymbols;
std::vector<DataRegionData> DataRegions;
/// The set of function symbols for which a .thumb_func directive has
/// been seen.
//
@ -883,6 +898,33 @@ public:
size_t indirect_symbol_size() const { return IndirectSymbols.size(); }
/// @}
/// @name Data Region List Access
/// @{
// FIXME: This is a total hack, this should not be here. Once things are
// factored so that the streamer has direct access to the .o writer, it can
// disappear.
std::vector<DataRegionData> &getDataRegions() {
return DataRegions;
}
data_region_iterator data_region_begin() {
return DataRegions.begin();
}
const_data_region_iterator data_region_begin() const {
return DataRegions.begin();
}
data_region_iterator data_region_end() {
return DataRegions.end();
}
const_data_region_iterator data_region_end() const {
return DataRegions.end();
}
size_t data_region_size() const { return DataRegions.size(); }
/// @}
/// @name Backend Data Access
/// @{

View File

@ -161,6 +161,10 @@ namespace llvm {
/// with a unique but unspecified name.
MCSymbol *CreateTempSymbol();
/// getUniqueSymbolID() - Return a unique identifier for use in constructing
/// symbol names.
unsigned getUniqueSymbolID() { return NextUniqueID++; }
/// CreateDirectionalLocalSymbol - Create the definition of a directional
/// local symbol for numbered label (used for "1:" definitions).
MCSymbol *CreateDirectionalLocalSymbol(int64_t LocalLabelVal);

View File

@ -52,6 +52,14 @@ enum MCAssemblerFlag {
MCAF_Code64 ///< .code64 (X86)
};
enum MCDataRegionType {
MCDR_DataRegion, ///< .data_region
MCDR_DataRegionJT8, ///< .data_region jt8
MCDR_DataRegionJT16, ///< .data_region jt16
MCDR_DataRegionJT32, ///< .data_region jt32
MCDR_DataRegionEnd ///< .end_data_region
};
} // end namespace llvm
#endif

View File

@ -179,6 +179,9 @@ public:
void WriteNlist(MachSymbolData &MSD, const MCAsmLayout &Layout);
void WriteLinkeditLoadCommand(uint32_t Type, uint32_t DataOffset,
uint32_t DataSize);
// FIXME: We really need to improve the relocation validation. Basically, we
// want to implement a separate computation which evaluates the relocation
// entry as the linker would, and verifies that the resultant fixup value is

View File

@ -69,22 +69,7 @@ namespace llvm {
SmallVector<std::pair<const MCSection *,
const MCSection *>, 4> SectionStack;
unsigned UniqueCodeBeginSuffix;
unsigned UniqueDataBeginSuffix;
protected:
/// Indicator of whether the previous data-or-code indicator was for
/// code or not. Used to determine when we need to emit a new indicator.
enum DataType {
Data,
Code,
JumpTable8,
JumpTable16,
JumpTable32
};
DataType RegionIndicator;
MCStreamer(MCContext &Ctx);
const MCExpr *BuildSymbolDiff(MCContext &Context, const MCSymbol *A,
@ -241,47 +226,15 @@ namespace llvm {
/// used in an assignment.
virtual void EmitLabel(MCSymbol *Symbol);
/// EmitDataRegion - Emit a label that marks the beginning of a data
/// region.
/// On ELF targets, this corresponds to an assembler statement such as:
/// $d.1:
virtual void EmitDataRegion();
/// EmitJumpTable8Region - Emit a label that marks the beginning of a
/// jump table composed of 8-bit offsets.
/// On ELF targets, this corresponds to an assembler statement such as:
/// $d.1:
virtual void EmitJumpTable8Region();
/// EmitJumpTable16Region - Emit a label that marks the beginning of a
/// jump table composed of 16-bit offsets.
/// On ELF targets, this corresponds to an assembler statement such as:
/// $d.1:
virtual void EmitJumpTable16Region();
/// EmitJumpTable32Region - Emit a label that marks the beginning of a
/// jump table composed of 32-bit offsets.
/// On ELF targets, this corresponds to an assembler statement such as:
/// $d.1:
virtual void EmitJumpTable32Region();
/// EmitCodeRegion - Emit a label that marks the beginning of a code
/// region.
/// On ELF targets, this corresponds to an assembler statement such as:
/// $a.1:
virtual void EmitCodeRegion();
/// ForceCodeRegion - Forcibly sets the current region mode to code. Used
/// at function entry points.
void ForceCodeRegion() { RegionIndicator = Code; }
virtual void EmitEHSymAttributes(const MCSymbol *Symbol,
MCSymbol *EHSymbol);
/// EmitAssemblerFlag - Note in the output the specified @p Flag
/// EmitAssemblerFlag - Note in the output the specified @p Flag.
virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) = 0;
/// EmitDataRegion - Note in the output the specified region @p Kind.
virtual void EmitDataRegion(MCDataRegionType Kind) {}
/// EmitThumbFunc - Note in the output that the specified @p Func is
/// a Thumb mode function (ARM target only).
virtual void EmitThumbFunc(MCSymbol *Func) = 0;

View File

@ -97,7 +97,8 @@ namespace macho {
DysymtabLoadCommandSize = 80,
Nlist32Size = 12,
Nlist64Size = 16,
RelocationInfoSize = 8
RelocationInfoSize = 8,
LinkeditLoadCommandSize = 16
};
/// \brief Constants for header magic field.
@ -140,7 +141,8 @@ namespace macho {
LCT_UUID = 0x1b,
LCT_CodeSignature = 0x1d,
LCT_SegmentSplitInfo = 0x1e,
LCT_FunctionStarts = 0x26
LCT_FunctionStarts = 0x26,
LCT_DataInCode = 0x29
};
/// \brief Load command structure.
@ -279,6 +281,18 @@ namespace macho {
uint64_t Value;
};
/// @}
/// @name Data-in-code Table Entry
/// @{
// See <mach-o/loader.h>.
enum DataRegionType { Data = 1, JumpTable8, JumpTable16, JumpTable32 };
struct DataInCodeTableEntry {
uint32_t Offset; /* from mach_header to start of data region */
uint16_t Length; /* number of bytes in data region */
uint16_t Kind; /* a DataRegionType value */
};
/// @}
/// @name Indirect Symbol Table
/// @{

View File

@ -174,6 +174,9 @@ public:
void ReadSymbol64TableEntry(
uint64_t SymbolTableOffset, unsigned Index,
InMemoryStruct<macho::Symbol64TableEntry> &Res) const;
void ReadDataInCodeTableEntry(
uint64_t TableOffset, unsigned Index,
InMemoryStruct<macho::DataInCodeTableEntry> &Res) const;
void ReadULEB128s(uint64_t Index, SmallVectorImpl<uint64_t> &Out) const;
/// @}

View File

@ -475,10 +475,8 @@ void AsmPrinter::EmitFunctionHeader() {
void AsmPrinter::EmitFunctionEntryLabel() {
// The function label could have already been emitted if two symbols end up
// conflicting due to asm renaming. Detect this and emit an error.
if (CurrentFnSym->isUndefined()) {
OutStreamer.ForceCodeRegion();
if (CurrentFnSym->isUndefined())
return OutStreamer.EmitLabel(CurrentFnSym);
}
report_fatal_error("'" + Twine(CurrentFnSym->getName()) +
"' label emitted multiple times to assembly file");
@ -1085,15 +1083,6 @@ void AsmPrinter::EmitJumpTableInfo() {
EmitAlignment(Log2_32(MJTI->getEntryAlignment(*TM.getTargetData())));
// If we know the form of the jump table, go ahead and tag it as such.
if (!JTInDiffSection) {
if (MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32) {
OutStreamer.EmitJumpTable32Region();
} else {
OutStreamer.EmitDataRegion();
}
}
for (unsigned JTI = 0, e = JT.size(); JTI != e; ++JTI) {
const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;

View File

@ -50,6 +50,7 @@ MCAsmInfo::MCAsmInfo() {
AllowNameToStartWithDigit = false;
AllowPeriodsInName = true;
AllowUTF8 = true;
UseDataRegionDirectives = false;
ZeroDirective = "\t.zero\t";
AsciiDirective = "\t.ascii\t";
AscizDirective = "\t.asciz\t";
@ -57,12 +58,6 @@ MCAsmInfo::MCAsmInfo() {
Data16bitsDirective = "\t.short\t";
Data32bitsDirective = "\t.long\t";
Data64bitsDirective = "\t.quad\t";
DataBegin = "$d.";
CodeBegin = "$a.";
JT8Begin = "$d.";
JT16Begin = "$d.";
JT32Begin = "$d.";
SupportsDataRegions = false;
SunStyleELFSectionSwitchSyntax = false;
UsesELFSectionDirectiveForBSS = false;
AlignDirective = "\t.align\t";

View File

@ -36,8 +36,6 @@ MCAsmInfoCOFF::MCAsmInfoCOFF() {
SupportsDebugInformation = true;
DwarfSectionOffsetDirective = "\t.secrel32\t";
HasMicrosoftFastStdCallMangling = true;
SupportsDataRegions = false;
}
void MCAsmInfoMicrosoft::anchor() { }

View File

@ -43,13 +43,6 @@ MCAsmInfoDarwin::MCAsmInfoDarwin() {
HasMachoTBSSDirective = true; // Uses .tbss
HasStaticCtorDtorReferenceInStaticMode = true;
CodeBegin = "L$start$code$";
DataBegin = "L$start$data$";
JT8Begin = "L$start$jt8$";
JT16Begin = "L$start$jt16$";
JT32Begin = "L$start$jt32$";
SupportsDataRegions = true;
// FIXME: Darwin 10 and newer don't need this.
LinkerRequiresNonEmptyDwarfLines = true;

View File

@ -138,6 +138,7 @@ public:
virtual void EmitEHSymAttributes(const MCSymbol *Symbol,
MCSymbol *EHSymbol);
virtual void EmitAssemblerFlag(MCAssemblerFlag Flag);
virtual void EmitDataRegion(MCDataRegionType Kind);
virtual void EmitThumbFunc(MCSymbol *Func);
virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value);
@ -352,6 +353,21 @@ void MCAsmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
EmitEOL();
}
void MCAsmStreamer::EmitDataRegion(MCDataRegionType Kind) {
MCContext &Ctx = getContext();
const MCAsmInfo &MAI = Ctx.getAsmInfo();
if (!MAI.doesSupportDataRegionDirectives())
return;
switch (Kind) {
case MCDR_DataRegion: OS << "\t.data_region"; break;
case MCDR_DataRegionJT8: OS << "\t.data_region jt8"; break;
case MCDR_DataRegionJT16: OS << "\t.data_region jt16"; break;
case MCDR_DataRegionJT32: OS << "\t.data_region jt32"; break;
case MCDR_DataRegionEnd: OS << "\t.end_data_region"; break;
}
EmitEOL();
}
void MCAsmStreamer::EmitThumbFunc(MCSymbol *Func) {
// This needs to emit to a temporary string to get properly quoted
// MCSymbols when they have spaces in them.

View File

@ -13,6 +13,8 @@
#include "MCELF.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"

View File

@ -1,4 +1,3 @@
//===- lib/MC/MCMachOStreamer.cpp - Mach-O Object Output ------------===//
//
// The LLVM Compiler Infrastructure
//
@ -33,6 +32,8 @@ class MCMachOStreamer : public MCObjectStreamer {
private:
virtual void EmitInstToData(const MCInst &Inst);
void EmitDataRegion(DataRegionData::KindTy Kind);
void EmitDataRegionEnd();
public:
MCMachOStreamer(MCContext &Context, MCAsmBackend &MAB,
raw_ostream &OS, MCCodeEmitter *Emitter)
@ -46,6 +47,7 @@ public:
virtual void EmitEHSymAttributes(const MCSymbol *Symbol,
MCSymbol *EHSymbol);
virtual void EmitAssemblerFlag(MCAssemblerFlag Flag);
virtual void EmitDataRegion(MCDataRegionType Kind);
virtual void EmitThumbFunc(MCSymbol *Func);
virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value);
virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute);
@ -138,6 +140,26 @@ void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) {
SD.setFlags(SD.getFlags() & ~SF_ReferenceTypeMask);
}
void MCMachOStreamer::EmitDataRegion(DataRegionData::KindTy Kind) {
// Create a temporary label to mark the start of the data region.
MCSymbol *Start = getContext().CreateTempSymbol();
EmitLabel(Start);
// Record the region for the object writer to use.
DataRegionData Data = { Kind, Start, NULL };
std::vector<DataRegionData> &Regions = getAssembler().getDataRegions();
Regions.push_back(Data);
}
void MCMachOStreamer::EmitDataRegionEnd() {
std::vector<DataRegionData> &Regions = getAssembler().getDataRegions();
assert(Regions.size() && "Mismatched .end_data_region!");
DataRegionData &Data = Regions.back();
assert(Data.End == NULL && "Mismatched .end_data_region!");
// Create a temporary label to mark the end of the data region.
Data.End = getContext().CreateTempSymbol();
EmitLabel(Data.End);
}
void MCMachOStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
// Let the target do whatever target specific stuff it needs to do.
getAssembler().getBackend().handleAssemblerFlag(Flag);
@ -153,6 +175,26 @@ void MCMachOStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
}
}
void MCMachOStreamer::EmitDataRegion(MCDataRegionType Kind) {
switch (Kind) {
case MCDR_DataRegion:
EmitDataRegion(DataRegionData::Data);
return;
case MCDR_DataRegionJT8:
EmitDataRegion(DataRegionData::JumpTable8);
return;
case MCDR_DataRegionJT16:
EmitDataRegion(DataRegionData::JumpTable16);
return;
case MCDR_DataRegionJT32:
EmitDataRegion(DataRegionData::JumpTable32);
return;
case MCDR_DataRegionEnd:
EmitDataRegionEnd();
return;
}
}
void MCMachOStreamer::EmitThumbFunc(MCSymbol *Symbol) {
// Remember that the function is a thumb function. Fixup and relocation
// values will need adjusted.

View File

@ -14,6 +14,7 @@
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCParser/MCAsmLexer.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/MemoryBuffer.h"
@ -56,6 +57,9 @@ public:
AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveTBSS>(".tbss");
AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveZerofill>(".zerofill");
AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveDataRegion>(".data_region");
AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveDataRegionEnd>(".end_data_region");
// Special section directives.
AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveConst>(".const");
AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveConstData>(".const_data");
@ -113,6 +117,8 @@ public:
bool ParseDirectiveSubsectionsViaSymbols(StringRef, SMLoc);
bool ParseDirectiveTBSS(StringRef, SMLoc);
bool ParseDirectiveZerofill(StringRef, SMLoc);
bool ParseDirectiveDataRegion(StringRef, SMLoc);
bool ParseDirectiveDataRegionEnd(StringRef, SMLoc);
// Named Section Directive
bool ParseSectionDirectiveConst(StringRef, SMLoc) {
@ -659,6 +665,42 @@ bool DarwinAsmParser::ParseDirectiveZerofill(StringRef, SMLoc) {
return false;
}
/// ParseDirectiveDataRegion
/// ::= .data_region [ ( jt8 | jt16 | jt32 ) ]
bool DarwinAsmParser::ParseDirectiveDataRegion(StringRef, SMLoc) {
if (getLexer().is(AsmToken::EndOfStatement)) {
Lex();
getStreamer().EmitDataRegion(MCDR_DataRegion);
return false;
}
StringRef RegionType;
SMLoc Loc = getParser().getTok().getLoc();
if (getParser().ParseIdentifier(RegionType))
return TokError("expected region type after '.data_region' directive");
int Kind = StringSwitch<int>(RegionType)
.Case("jt8", MCDR_DataRegionJT8)
.Case("jt16", MCDR_DataRegionJT16)
.Case("jt32", MCDR_DataRegionJT32)
.Default(-1);
if (Kind == -1)
return Error(Loc, "unknown region type in '.data_region' directive");
Lex();
getStreamer().EmitDataRegion((MCDataRegionType)Kind);
return false;
}
/// ParseDirectiveDataRegionEnd
/// ::= .end_data_region
bool DarwinAsmParser::ParseDirectiveDataRegionEnd(StringRef, SMLoc) {
if (getLexer().isNot(AsmToken::EndOfStatement))
return TokError("unexpected token in '.end_data_region' directive");
Lex();
getStreamer().EmitDataRegion(MCDR_DataRegionEnd);
return false;
}
namespace llvm {
MCAsmParserExtension *createDarwinAsmParser() {

View File

@ -20,12 +20,9 @@
#include <cstdlib>
using namespace llvm;
MCStreamer::MCStreamer(MCContext &Ctx) : Context(Ctx), EmitEHFrame(true),
EmitDebugFrame(false),
CurrentW64UnwindInfo(0),
LastSymbol(0),
UniqueCodeBeginSuffix(0),
UniqueDataBeginSuffix(0) {
MCStreamer::MCStreamer(MCContext &Ctx)
: Context(Ctx), EmitEHFrame(true), EmitDebugFrame(false),
CurrentW64UnwindInfo(0), LastSymbol(0) {
const MCSection *section = NULL;
SectionStack.push_back(std::make_pair(section, section));
}
@ -183,85 +180,6 @@ void MCStreamer::EmitLabel(MCSymbol *Symbol) {
LastSymbol = Symbol;
}
void MCStreamer::EmitDataRegion() {
if (RegionIndicator == Data) return;
MCContext &Context = getContext();
const MCAsmInfo &MAI = Context.getAsmInfo();
if (!MAI.getSupportsDataRegions()) return;
// Generate a unique symbol name.
MCSymbol *NewSym = Context.GetOrCreateSymbol(MAI.getDataBeginLabelName() +
Twine(UniqueDataBeginSuffix++));
EmitLabel(NewSym);
RegionIndicator = Data;
}
void MCStreamer::EmitCodeRegion() {
if (RegionIndicator == Code) return;
MCContext &Context = getContext();
const MCAsmInfo &MAI = Context.getAsmInfo();
if (!MAI.getSupportsDataRegions()) return;
// Generate a unique symbol name.
MCSymbol *NewSym = Context.GetOrCreateSymbol(MAI.getCodeBeginLabelName() +
Twine(UniqueCodeBeginSuffix++));
EmitLabel(NewSym);
RegionIndicator = Code;
}
void MCStreamer::EmitJumpTable8Region() {
if (RegionIndicator == JumpTable8) return;
MCContext &Context = getContext();
const MCAsmInfo &MAI = Context.getAsmInfo();
if (!MAI.getSupportsDataRegions()) return;
// Generate a unique symbol name.
MCSymbol *NewSym =
Context.GetOrCreateSymbol(MAI.getJumpTable8BeginLabelName() +
Twine(UniqueDataBeginSuffix++));
EmitLabel(NewSym);
RegionIndicator = JumpTable8;
}
void MCStreamer::EmitJumpTable16Region() {
if (RegionIndicator == JumpTable16) return;
MCContext &Context = getContext();
const MCAsmInfo &MAI = Context.getAsmInfo();
if (!MAI.getSupportsDataRegions()) return;
// Generate a unique symbol name.
MCSymbol *NewSym =
Context.GetOrCreateSymbol(MAI.getJumpTable16BeginLabelName() +
Twine(UniqueDataBeginSuffix++));
EmitLabel(NewSym);
RegionIndicator = JumpTable16;
}
void MCStreamer::EmitJumpTable32Region() {
if (RegionIndicator == JumpTable32) return;
MCContext &Context = getContext();
const MCAsmInfo &MAI = Context.getAsmInfo();
if (!MAI.getSupportsDataRegions()) return;
// Generate a unique symbol name.
MCSymbol *NewSym =
Context.GetOrCreateSymbol(MAI.getJumpTable32BeginLabelName() +
Twine(UniqueDataBeginSuffix++));
EmitLabel(NewSym);
RegionIndicator = JumpTable32;
}
void MCStreamer::EmitCompactUnwindEncoding(uint32_t CompactUnwindEncoding) {
EnsureValidFrame();
MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo();
@ -283,7 +201,6 @@ void MCStreamer::EmitCFIStartProc() {
EmitCFIStartProcImpl(Frame);
FrameInfos.push_back(Frame);
RegionIndicator = Code;
}
void MCStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {

View File

@ -21,6 +21,7 @@
#include "llvm/MC/MCMachOSymbolFlags.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Object/MachOFormat.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include <vector>
@ -351,6 +352,21 @@ void MachObjectWriter::WriteNlist(MachSymbolData &MSD,
Write32(Address);
}
void MachObjectWriter::WriteLinkeditLoadCommand(uint32_t Type,
uint32_t DataOffset,
uint32_t DataSize) {
uint64_t Start = OS.tell();
(void) Start;
Write32(Type);
Write32(macho::LinkeditLoadCommandSize);
Write32(DataOffset);
Write32(DataSize);
assert(OS.tell() - Start == macho::LinkeditLoadCommandSize);
}
void MachObjectWriter::RecordRelocation(const MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCFragment *Fragment,
@ -654,6 +670,13 @@ void MachObjectWriter::WriteObject(MCAssembler &Asm,
macho::DysymtabLoadCommandSize);
}
// Add the data-in-code load command size, if used.
unsigned NumDataRegions = Asm.getDataRegions().size();
if (NumDataRegions) {
++NumLoadCommands;
LoadCommandsSize += macho::LinkeditLoadCommandSize;
}
// Compute the total size of the section data, as well as its file size and vm
// size.
uint64_t SectionDataStart = (is64Bit() ? macho::Header64Size :
@ -701,6 +724,15 @@ void MachObjectWriter::WriteObject(MCAssembler &Asm,
RelocTableEnd += NumRelocs * macho::RelocationInfoSize;
}
// Write the data-in-code load command, if used.
uint64_t DataInCodeTableEnd = RelocTableEnd + NumDataRegions * 8;
if (NumDataRegions) {
uint64_t DataRegionsOffset = RelocTableEnd;
uint64_t DataRegionsSize = NumDataRegions * 8;
WriteLinkeditLoadCommand(macho::LCT_DataInCode, DataRegionsOffset,
DataRegionsSize);
}
// Write the symbol table load command, if used.
if (NumSymbols) {
unsigned FirstLocalSymbol = 0;
@ -717,10 +749,10 @@ void MachObjectWriter::WriteObject(MCAssembler &Asm,
// If used, the indirect symbols are written after the section data.
if (NumIndirectSymbols)
IndirectSymbolOffset = RelocTableEnd;
IndirectSymbolOffset = DataInCodeTableEnd;
// The symbol table is written after the indirect symbol data.
uint64_t SymbolTableOffset = RelocTableEnd + IndirectSymbolSize;
uint64_t SymbolTableOffset = DataInCodeTableEnd + IndirectSymbolSize;
// The string table is written after symbol table.
uint64_t StringTableOffset =
@ -760,6 +792,23 @@ void MachObjectWriter::WriteObject(MCAssembler &Asm,
}
}
// Write out the data-in-code region payload, if there is one.
for (MCAssembler::const_data_region_iterator
it = Asm.data_region_begin(), ie = Asm.data_region_end();
it != ie; ++it) {
const DataRegionData *Data = &(*it);
uint64_t Start = getSymbolAddress(&Layout.getAssembler().getSymbolData(*Data->Start), Layout);
uint64_t End = getSymbolAddress(&Layout.getAssembler().getSymbolData(*Data->End), Layout);
DEBUG(dbgs() << "data in code region-- kind: " << Data->Kind
<< " start: " << Start << "(" << Data->Start->getName() << ")"
<< " end: " << End << "(" << Data->End->getName() << ")"
<< " size: " << End - Start
<< "\n");
Write32(Start);
Write16(End - Start);
Write16(Data->Kind);
}
// Write the symbol table data, if used.
if (NumSymbols) {
// Write the indirect symbol entries.

View File

@ -357,6 +357,19 @@ void MachOObject::ReadSymbol64TableEntry(uint64_t SymbolTableOffset,
ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res);
}
template<>
void SwapStruct(macho::DataInCodeTableEntry &Value) {
SwapValue(Value.Offset);
SwapValue(Value.Length);
SwapValue(Value.Kind);
}
void MachOObject::ReadDataInCodeTableEntry(uint64_t TableOffset,
unsigned Index,
InMemoryStruct<macho::DataInCodeTableEntry> &Res) const {
uint64_t Offset = (TableOffset +
Index * sizeof(macho::DataInCodeTableEntry));
ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res);
}
void MachOObject::ReadULEB128s(uint64_t Index,
SmallVectorImpl<uint64_t> &Out) const {

View File

@ -283,9 +283,16 @@ void ARMAsmPrinter::EmitDwarfRegOp(const MachineLocation &MLoc) const {
}
}
void ARMAsmPrinter::EmitFunctionEntryLabel() {
OutStreamer.ForceCodeRegion();
void ARMAsmPrinter::EmitFunctionBodyEnd() {
// Make sure to terminate any constant pools that were at the end
// of the function.
if (!InConstantPool)
return;
InConstantPool = false;
OutStreamer.EmitDataRegion(MCDR_DataRegionEnd);
}
void ARMAsmPrinter::EmitFunctionEntryLabel() {
if (AFI->isThumbFunction()) {
OutStreamer.EmitAssemblerFlag(MCAF_Code16);
OutStreamer.EmitThumbFunc(CurrentFnSym);
@ -934,13 +941,13 @@ void ARMAsmPrinter::EmitJumpTable(const MachineInstr *MI) {
const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id
unsigned JTI = MO1.getIndex();
// Tag the jump table appropriately for precise disassembly.
OutStreamer.EmitJumpTable32Region();
// Emit a label for the jump table.
MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm());
OutStreamer.EmitLabel(JTISymbol);
// Mark the jump table as data-in-code.
OutStreamer.EmitDataRegion(MCDR_DataRegionJT32);
// Emit each entry of the table.
const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
@ -969,6 +976,8 @@ void ARMAsmPrinter::EmitJumpTable(const MachineInstr *MI) {
OutContext);
OutStreamer.EmitValue(Expr, 4);
}
// Mark the end of jump table data-in-code region.
OutStreamer.EmitDataRegion(MCDR_DataRegionEnd);
}
void ARMAsmPrinter::EmitJump2Table(const MachineInstr *MI) {
@ -978,15 +987,6 @@ void ARMAsmPrinter::EmitJump2Table(const MachineInstr *MI) {
const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id
unsigned JTI = MO1.getIndex();
// Emit a label for the jump table.
if (MI->getOpcode() == ARM::t2TBB_JT) {
OutStreamer.EmitJumpTable8Region();
} else if (MI->getOpcode() == ARM::t2TBH_JT) {
OutStreamer.EmitJumpTable16Region();
} else {
OutStreamer.EmitJumpTable32Region();
}
MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm());
OutStreamer.EmitLabel(JTISymbol);
@ -995,10 +995,15 @@ void ARMAsmPrinter::EmitJump2Table(const MachineInstr *MI) {
const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
unsigned OffsetWidth = 4;
if (MI->getOpcode() == ARM::t2TBB_JT)
if (MI->getOpcode() == ARM::t2TBB_JT) {
OffsetWidth = 1;
else if (MI->getOpcode() == ARM::t2TBH_JT)
// Mark the jump table as data-in-code.
OutStreamer.EmitDataRegion(MCDR_DataRegionJT8);
} else if (MI->getOpcode() == ARM::t2TBH_JT) {
OffsetWidth = 2;
// Mark the jump table as data-in-code.
OutStreamer.EmitDataRegion(MCDR_DataRegionJT16);
}
for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) {
MachineBasicBlock *MBB = JTBBs[i];
@ -1031,6 +1036,8 @@ void ARMAsmPrinter::EmitJump2Table(const MachineInstr *MI) {
OutContext);
OutStreamer.EmitValue(Expr, OffsetWidth);
}
// Mark the end of jump table data-in-code region.
OutStreamer.EmitDataRegion(MCDR_DataRegionEnd);
}
void ARMAsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
@ -1208,8 +1215,11 @@ extern cl::opt<bool> EnableARMEHABI;
#include "ARMGenMCPseudoLowering.inc"
void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
if (MI->getOpcode() != ARM::CONSTPOOL_ENTRY)
OutStreamer.EmitCodeRegion();
// If we just ended a constant pool, mark it as such.
if (InConstantPool && MI->getOpcode() != ARM::CONSTPOOL_ENTRY) {
OutStreamer.EmitDataRegion(MCDR_DataRegionEnd);
InConstantPool = false;
}
// Emit unwinding stuff for frame-related instructions
if (EnableARMEHABI && MI->getFlag(MachineInstr::FrameSetup))
@ -1565,9 +1575,12 @@ void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
unsigned LabelId = (unsigned)MI->getOperand(0).getImm();
unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex();
// Mark the constant pool entry as data if we're not already in a data
// region.
OutStreamer.EmitDataRegion();
// If this is the first entry of the pool, mark it.
if (!InConstantPool) {
OutStreamer.EmitDataRegion(MCDR_DataRegion);
InConstantPool = true;
}
OutStreamer.EmitLabel(GetCPISymbol(LabelId));
const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx];

View File

@ -44,9 +44,12 @@ class LLVM_LIBRARY_VISIBILITY ARMAsmPrinter : public AsmPrinter {
/// MachineFunction.
const MachineConstantPool *MCP;
/// InConstantPool - Maintain state when emitting a sequence of constant
/// pool entries so we can properly mark them as data regions.
bool InConstantPool;
public:
explicit ARMAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
: AsmPrinter(TM, Streamer), AFI(NULL), MCP(NULL) {
: AsmPrinter(TM, Streamer), AFI(NULL), MCP(NULL), InConstantPool(false) {
Subtarget = &TM.getSubtarget<ARMSubtarget>();
}
@ -70,6 +73,7 @@ public:
bool runOnMachineFunction(MachineFunction &F);
virtual void EmitConstantPool() {} // we emit constant pools customly!
virtual void EmitFunctionBodyEnd();
virtual void EmitFunctionEntryLabel();
void EmitStartOfAsmFile(Module &M);
void EmitEndOfAsmFile(Module &M);

View File

@ -29,6 +29,7 @@ ARMMCAsmInfoDarwin::ARMMCAsmInfoDarwin() {
CommentString = "@";
Code16Directive = ".code\t16";
Code32Directive = ".code\t32";
UseDataRegionDirectives = true;
SupportsDebugInformation = true;

View File

@ -610,8 +610,6 @@ static void LowerTlsAddr(MCStreamer &OutStreamer,
}
void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
OutStreamer.EmitCodeRegion();
X86MCInstLower MCInstLowering(Mang, *MF, *this);
switch (MI->getOpcode()) {
case TargetOpcode::DBG_VALUE:

View File

@ -0,0 +1,42 @@
; RUN: llc < %s -mtriple=armv7-apple-darwin | FileCheck %s
define double @f1() nounwind {
; CHECK: f1:
; CHECK: .data_region
; CHECK: .long 1413754129
; CHECK: .long 1074340347
; CHECK: .end_data_region
ret double 0x400921FB54442D11
}
define i32 @f2() {
; CHECK: f2:
; CHECK: .data_region jt32
; CHECK: .end_data_region
entry:
switch i32 undef, label %return [
i32 1, label %sw.bb
i32 2, label %sw.bb6
i32 3, label %sw.bb13
i32 4, label %sw.bb20
]
sw.bb: ; preds = %entry
br label %return
sw.bb6: ; preds = %entry
br label %return
sw.bb13: ; preds = %entry
br label %return
sw.bb20: ; preds = %entry
%div = sdiv i32 undef, undef
br label %return
return: ; preds = %sw.bb20, %sw.bb13, %sw.bb6, %sw.bb, %entry
%retval.0 = phi i32 [ %div, %sw.bb20 ], [ undef, %sw.bb13 ], [ undef, %sw.bb6 ], [ undef, %sw.bb ], [ 0, %entry ]
ret i32 %retval.0
}

View File

@ -5,7 +5,9 @@ define void @bar(i32 %n.u) {
entry:
; CHECK: bar:
; CHECK: tbb
; CHECK: .align 1
; CHECK: .data_region jt8
; CHECK: .end_data_region
; CHECK-NEXT: .align 1
switch i32 %n.u, label %bb12 [i32 1, label %bb i32 2, label %bb6 i32 4, label %bb7 i32 5, label %bb8 i32 6, label %bb10 i32 7, label %bb1 i32 8, label %bb3 i32 9, label %bb4 i32 10, label %bb9 i32 11, label %bb2 i32 12, label %bb5 i32 13, label %bb11 ]
bb:

View File

@ -61,7 +61,7 @@ bb3: ; preds = %bb, %entry
declare void @exit(i32) noreturn nounwind
;; OBJ: Relocation 1
;; OBJ-NEXT: 'r_offset',
;; OBJ-NEXT: 'r_offset',
;; OBJ-NEXT: 'r_sym', 0x000002
;; OBJ-NEXT: 'r_type', 0x2b

View File

@ -0,0 +1,33 @@
@ RUN: llvm-mc -triple armv7-apple-darwin10 -filetype=obj -o - < %s | macho-dump | FileCheck %s
.text
_foo:
@ CHECK: # DICE 0
@ CHECK: ('offset', 0)
@ CHECK: ('length', 4)
@ CHECK: ('kind', 1)
@ CHECK: # DICE 1
@ CHECK: ('offset', 4)
@ CHECK: ('length', 4)
@ CHECK: ('kind', 4)
@ CHECK: # DICE 2
@ CHECK: ('offset', 8)
@ CHECK: ('length', 2)
@ CHECK: ('kind', 3)
@ CHECK: # DICE 3
@ CHECK: ('offset', 10)
@ CHECK: ('length', 1)
@ CHECK: ('kind', 2)
.data_region
.long 10
.end_data_region
.data_region jt32
.long 1
.end_data_region
.data_region jt16
.short 2
.end_data_region
.data_region jt8
.byte 3
.end_data_region

View File

@ -332,6 +332,35 @@ static int DumpLinkeditDataCommand(MachOObject &Obj,
return 0;
}
static int DumpDataInCodeDataCommand(MachOObject &Obj,
const MachOObject::LoadCommandInfo &LCI) {
InMemoryStruct<macho::LinkeditDataLoadCommand> LLC;
Obj.ReadLinkeditDataLoadCommand(LCI, LLC);
if (!LLC)
return Error("unable to read segment load command");
outs() << " ('dataoff', " << LLC->DataOffset << ")\n"
<< " ('datasize', " << LLC->DataSize << ")\n"
<< " ('_data_regions', [\n";
unsigned NumRegions = LLC->DataSize / 8;
for (unsigned i = 0; i < NumRegions; ++i) {
InMemoryStruct<macho::DataInCodeTableEntry> DICE;
Obj.ReadDataInCodeTableEntry(LLC->DataOffset, i, DICE);
if (!DICE)
return Error("unable to read DataInCodeTableEntry");
outs() << " # DICE " << i << "\n"
<< " ('offset', " << DICE->Offset << ")\n"
<< " ('length', " << DICE->Length << ")\n"
<< " ('kind', " << DICE->Kind << ")\n";
}
outs() <<" ])\n";
return 0;
}
static int DumpLoadCommand(MachOObject &Obj, unsigned Index) {
const MachOObject::LoadCommandInfo &LCI = Obj.getLoadCommandInfo(Index);
@ -358,6 +387,9 @@ static int DumpLoadCommand(MachOObject &Obj, unsigned Index) {
case macho::LCT_FunctionStarts:
Res = DumpLinkeditDataCommand(Obj, LCI);
break;
case macho::LCT_DataInCode:
Res = DumpDataInCodeDataCommand(Obj, LCI);
break;
default:
Warning("unknown load command: " + Twine(LCI.Command.Type));
break;