summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 18e2f6e)
raw | patch | inline | side by side (parent: 18e2f6e)
author | Jim Grosbach <grosbach@apple.com> | |
Fri, 18 May 2012 19:12:01 +0000 (19:12 +0000) | ||
committer | Jim Grosbach <grosbach@apple.com> | |
Fri, 18 May 2012 19:12:01 +0000 (19:12 +0000) |
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
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@157062 91177308-0d34-0410-b5e6-96231b3b80d8
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
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@157062 91177308-0d34-0410-b5e6-96231b3b80d8
28 files changed:
index 16964c3c9d8fcf90e860a89dc2256b1913a57343..ae0dad2fd1c0578f2673e4d52b9b8bdb25dcddc8 100644 (file)
// 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
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.
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.
bool doesAllowUTF8() const {
return AllowUTF8;
}
+ bool doesSupportDataRegionDirectives() const {
+ return UseDataRegionDirectives;
+ }
const char *getZeroDirective() const {
return ZeroDirective;
}
index d139173c3e13f27f373311f1d3b3add1280ffd45..4ab7f91f72a5b6325ae0029688c5eef7e44d74d6 100644 (file)
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;
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
std::vector<IndirectSymbolData> IndirectSymbols;
+ std::vector<DataRegionData> DataRegions;
/// The set of function symbols for which a .thumb_func directive has
/// been seen.
//
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
/// @{
index b58631919330d68b1aa06b63972753d2d3a3dca3..59545d31a6551bfecd90c77954fe142be1805e7e 100644 (file)
/// 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);
index 9180d1b369fed0a389bd16ddb2015dbe117a03d1..0461766c2fd3c0ac71aadb37f51e1f9b0f45b914 100644 (file)
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
index 9bb598f5468a9707dc1017d864677f7825847f95..949d90700e083e10e87990200131ae5271092b70 100644 (file)
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
index 25956008e021f7dd6cf34327e40a618763d82c71..44c5fefaa1d9aa34128b18b7263ae4b02fb2c6a5 100644 (file)
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,
/// 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;
index 089cde92a0a368c124c635e4d4f1f29b0d0194d4..f30d431b69da61449401f5a5fbac0ec2a703c4a7 100644 (file)
DysymtabLoadCommandSize = 80,
Nlist32Size = 12,
Nlist64Size = 16,
- RelocationInfoSize = 8
+ RelocationInfoSize = 8,
+ LinkeditLoadCommandSize = 16
};
/// \brief Constants for header magic field.
LCT_UUID = 0x1b,
LCT_CodeSignature = 0x1d,
LCT_SegmentSplitInfo = 0x1e,
- LCT_FunctionStarts = 0x26
+ LCT_FunctionStarts = 0x26,
+ LCT_DataInCode = 0x29
};
/// \brief Load command structure.
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
/// @{
index 0560402743196a8dc5a3d4ce8efb92597cdf468c..86f150a2940f1cc4211a6eb0a6f99dc50d047009 100644 (file)
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;
/// @}
index b0b2ff4882afaec30a2ae4c7577fab87c1283c00..ae498dd27d356c694202ece3444e8d20ba89bce9 100644 (file)
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");
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;
diff --git a/lib/MC/MCAsmInfo.cpp b/lib/MC/MCAsmInfo.cpp
index 2456858ded4313bfe85f4ac7e244f1d8c512bdf2..d9c1d51d185fbc451ee11da5aa2abd95df1c116f 100644 (file)
--- a/lib/MC/MCAsmInfo.cpp
+++ b/lib/MC/MCAsmInfo.cpp
AllowNameToStartWithDigit = false;
AllowPeriodsInName = true;
AllowUTF8 = true;
+ UseDataRegionDirectives = false;
ZeroDirective = "\t.zero\t";
AsciiDirective = "\t.ascii\t";
AscizDirective = "\t.asciz\t";
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";
index 89413652ef0cc814b8c3f6011435f48e6734e29d..678e75af5dab4e8c72c3a7f6c82cff164307ac62 100644 (file)
--- a/lib/MC/MCAsmInfoCOFF.cpp
+++ b/lib/MC/MCAsmInfoCOFF.cpp
SupportsDebugInformation = true;
DwarfSectionOffsetDirective = "\t.secrel32\t";
HasMicrosoftFastStdCallMangling = true;
-
- SupportsDataRegions = false;
}
void MCAsmInfoMicrosoft::anchor() { }
index 4d675929e1ea416488071cc5305fa2583e786820..73ef7ba0604a0cfd014518363809c43fad28c8f8 100644 (file)
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;
index 3ce84c2cd9708dc26e230b496c3ac1f27f5a0e2d..9497b6be491c66570c6a7ce9c5ce508708d35f30 100644 (file)
--- a/lib/MC/MCAsmStreamer.cpp
+++ b/lib/MC/MCAsmStreamer.cpp
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);
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.
index 6c4d0e33a115ecbb93a42a0ccd9a2b35e16d139d..6ac9d9d51cbc77333e6b285fb579553f1793c498 100644 (file)
--- a/lib/MC/MCELFStreamer.cpp
+++ b/lib/MC/MCELFStreamer.cpp
#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"
index bc6cf773217cd0e72c228180e715e25c5e2e9fc8..970aa8baf43c094c390be5b6add172ed509d669e 100644 (file)
-//===- lib/MC/MCMachOStreamer.cpp - Mach-O Object Output ------------===//
//
// The LLVM Compiler Infrastructure
//
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)
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);
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);
}
}
+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.
index 6f450682cbebd46d49f13cc714b878738addfbfb..5662fea86ced2f13e99413aaaeff9fc1c84d6c47 100644 (file)
#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"
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");
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) {
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() {
diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp
index 43e62ff89a0fe1eb9efd9d8b024aadfe07a56f08..e363f28f7725d7243a595e56a2713a8f609ec087 100644 (file)
--- a/lib/MC/MCStreamer.cpp
+++ b/lib/MC/MCStreamer.cpp
#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));
}
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();
EmitCFIStartProcImpl(Frame);
FrameInfos.push_back(Frame);
- RegionIndicator = Code;
}
void MCStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
index 8e4066c894ba68f7621f46e6cc853dd87658c015..5820a224c527b57f060d3212fc36512de3649079 100644 (file)
#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>
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,
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 :
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;
// 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 =
}
}
+ // 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.
index b7e5cdcd6b846c33d1c18bd5d6715383e18e9286..00dea3fe476973ca642795b63d77c177d6236dc8 100644 (file)
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 {
index 410790a7baa03872ea8172364475acd96f08a1f9..e781498f1dfd31bb96b3959a78b1aca69ea9974d 100644 (file)
}
}
-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);
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();
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) {
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);
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];
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,
#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))
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];
index af3f75a0e8925c9d798ffcbd0666f91bfbee4c2e..3555e8f50a0d35a72a77cd3526f0437ebbf975df 100644 (file)
/// 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>();
}
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);
diff --git a/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp b/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp
index 4ac7741ba5b730026e9513630ebd91233c873b7c..d32805e522a378f96396524cb25e4b0af4ccd5ac 100644 (file)
CommentString = "@";
Code16Directive = ".code\t16";
Code32Directive = ".code\t32";
+ UseDataRegionDirectives = true;
SupportsDebugInformation = true;
index 54bfce1298cc93635a89147ef8d8fa9edb2a8349..2f368b6a5ac3eb8f5e6a7f402c51282b8e7261fa 100644 (file)
}
void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
- OutStreamer.EmitCodeRegion();
-
X86MCInstLower MCInstLowering(Mang, *MF, *this);
switch (MI->getOpcode()) {
case TargetOpcode::DBG_VALUE:
diff --git a/test/CodeGen/ARM/data-in-code-annotations.ll b/test/CodeGen/ARM/data-in-code-annotations.ll
--- /dev/null
@@ -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
+}
index 5dc3cc3ce70a9bd5860131e159be43d85daef617..a9d71d6bda15fe2353b7b9e29d6b700d331f71ec 100644 (file)
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:
index 6899d92b50f8c8744f49c234a4729ca0eae92c82..c98026b6a0437e712f91d5f51f33873dd01890ec 100644 (file)
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
diff --git a/test/MC/MachO/ARM/data-in-code.s b/test/MC/MachO/ARM/data-in-code.s
--- /dev/null
@@ -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
+
index f65c79595a95350c72cc502599e9dac390be0e4e..20deda9a0cbd8f1d0faf5b873554df8722de6770 100644 (file)
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);
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;