[llvm-commits] [llvm] r79652 - in /llvm/trunk: include/llvm/MC/MCAssembler.h lib/MC/MCAssembler.cpp lib/MC/MCMachOStreamer.cpp test/MC/MachO/data.s
Daniel Dunbar
daniel at zuster.org
Fri Aug 21 11:29:01 PDT 2009
Author: ddunbar
Date: Fri Aug 21 13:29:01 2009
New Revision: 79652
URL: http://llvm.org/viewvc/llvm-project?rev=79652&view=rev
Log:
llvm-mc/Mach-O: Support byte and fill value emission.
Added:
llvm/trunk/test/MC/MachO/data.s
Modified:
llvm/trunk/include/llvm/MC/MCAssembler.h
llvm/trunk/lib/MC/MCAssembler.cpp
llvm/trunk/lib/MC/MCMachOStreamer.cpp
Modified: llvm/trunk/include/llvm/MC/MCAssembler.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCAssembler.h?rev=79652&r1=79651&r2=79652&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCAssembler.h (original)
+++ llvm/trunk/include/llvm/MC/MCAssembler.h Fri Aug 21 13:29:01 2009
@@ -10,8 +10,11 @@
#ifndef LLVM_MC_MCASSEMBLER_H
#define LLVM_MC_MCASSEMBLER_H
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/ilist.h"
#include "llvm/ADT/ilist_node.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/DataTypes.h"
namespace llvm {
@@ -25,7 +28,211 @@
void operator=(const MCFragment&); // DO NOT IMPLEMENT
public:
- MCFragment(MCSectionData *SD = 0);
+ enum FragmentType {
+ FT_Data,
+ FT_Align,
+ FT_Fill,
+ FT_Org
+ };
+
+private:
+ FragmentType Kind;
+
+ /// @name Assembler Backend Data
+ /// @{
+ //
+ // FIXME: This could all be kept private to the assembler implementation.
+
+ /// FileOffset - The offset of this section in the object file. This is ~0
+ /// until initialized.
+ uint64_t FileOffset;
+
+ /// FileSize - The size of this section in the object file. This is ~0 until
+ /// initialized.
+ uint64_t FileSize;
+
+ /// @}
+
+protected:
+ MCFragment(FragmentType _Kind, MCSectionData *SD = 0);
+
+public:
+ // Only for sentinel.
+ MCFragment();
+ virtual ~MCFragment();
+
+ FragmentType getKind() const { return Kind; }
+
+ // FIXME: This should be abstract, fix sentinel.
+ virtual unsigned getMaxFileSize() const {
+ assert(0 && "Invalid getMaxFileSize call !");
+ };
+
+ /// @name Assembler Backend Support
+ /// @{
+ //
+ // FIXME: This could all be kept private to the assembler implementation.
+
+ unsigned getFileSize() const {
+ assert(FileSize != ~UINT64_C(0) && "File size not set!");
+ return FileSize;
+ }
+ void setFileSize(uint64_t Value) {
+ assert(Value <= getMaxFileSize() && "Invalid file size!");
+ FileSize = Value;
+ }
+
+ uint64_t getFileOffset() const {
+ assert(FileOffset != ~UINT64_C(0) && "File offset not set!");
+ return FileOffset;
+ }
+ void setFileOffset(uint64_t Value) { FileOffset = Value; }
+
+ /// @}
+
+ static bool classof(const MCFragment *O) { return true; }
+};
+
+class MCDataFragment : public MCFragment {
+ SmallString<32> Contents;
+
+public:
+ MCDataFragment(MCSectionData *SD = 0) : MCFragment(FT_Data, SD) {}
+
+ /// @name Accessors
+ /// @{
+
+ unsigned getMaxFileSize() const {
+ return Contents.size();
+ }
+
+ SmallString<32> &getContents() { return Contents; }
+ const SmallString<32> &getContents() const { return Contents; }
+
+ /// @}
+
+ static bool classof(const MCFragment *F) {
+ return F->getKind() == MCFragment::FT_Data;
+ }
+ static bool classof(const MCDataFragment *) { return true; }
+};
+
+class MCAlignFragment : public MCFragment {
+ /// Alignment - The alignment to ensure, in bytes.
+ unsigned Alignment;
+
+ /// Value - Value to use for filling padding bytes.
+ int64_t Value;
+
+ /// ValueSize - The size of the integer (in bytes) of \arg Value.
+ unsigned ValueSize;
+
+ /// MaxBytesToEmit - The maximum number of bytes to emit; if the alignment
+ /// cannot be satisfied in this width then this fragment is ignored.
+ unsigned MaxBytesToEmit;
+
+public:
+ MCAlignFragment(unsigned _Alignment, int64_t _Value, unsigned _ValueSize,
+ unsigned _MaxBytesToEmit, MCSectionData *SD = 0)
+ : MCFragment(FT_Align, SD), Alignment(_Alignment),
+ Value(_Value),ValueSize(_ValueSize),
+ MaxBytesToEmit(_MaxBytesToEmit) {}
+
+ /// @name Accessors
+ /// @{
+
+ unsigned getMaxFileSize() const {
+ return std::max(Alignment - 1, MaxBytesToEmit);
+ }
+
+ unsigned getAlignment() const { return Alignment; }
+
+ int64_t getValue() const { return Value; }
+
+ unsigned getValueSize() const { return ValueSize; }
+
+ unsigned getMaxBytesToEmit() const { return MaxBytesToEmit; }
+
+ /// @}
+
+ static bool classof(const MCFragment *F) {
+ return F->getKind() == MCFragment::FT_Align;
+ }
+ static bool classof(const MCAlignFragment *) { return true; }
+};
+
+class MCFillFragment : public MCFragment {
+ /// Value - Value to use for filling bytes.
+ MCValue Value;
+
+ /// ValueSize - The size (in bytes) of \arg Value to use when filling.
+ unsigned ValueSize;
+
+ /// Count - The number of copies of \arg Value to insert.
+ uint64_t Count;
+
+public:
+ MCFillFragment(MCValue _Value, unsigned _ValueSize, uint64_t _Count,
+ MCSectionData *SD = 0)
+ : MCFragment(FT_Fill, SD),
+ Value(_Value), ValueSize(_ValueSize), Count(_Count) {}
+
+ /// @name Accessors
+ /// @{
+
+ unsigned getMaxFileSize() const {
+ return ValueSize * Count;
+ }
+
+ MCValue getValue() const { return Value; }
+
+ unsigned getValueSize() const { return ValueSize; }
+
+ uint64_t getCount() const { return Count; }
+
+ /// @}
+
+ static bool classof(const MCFragment *F) {
+ return F->getKind() == MCFragment::FT_Fill;
+ }
+ static bool classof(const MCFillFragment *) { return true; }
+};
+
+class MCOrgFragment : public MCFragment {
+ /// Offset - The offset this fragment should start at.
+ MCValue Offset;
+
+ /// Value - Value to use for filling bytes.
+ int64_t Value;
+
+ /// ValueSize - The size (in bytes) of \arg Value to use when filling.
+ unsigned ValueSize;
+
+public:
+ MCOrgFragment(MCValue _Offset, int64_t _Value, unsigned _ValueSize,
+ MCSectionData *SD = 0)
+ : MCFragment(FT_Org, SD),
+ Offset(_Offset), Value(_Value), ValueSize(_ValueSize) {}
+ /// @name Accessors
+ /// @{
+
+ unsigned getMaxFileSize() const {
+ // FIXME
+ return 0;
+ }
+
+ MCValue getOffset() const { return Offset; }
+
+ int64_t getValue() const { return Value; }
+
+ unsigned getValueSize() const { return ValueSize; }
+
+ /// @}
+
+ static bool classof(const MCFragment *F) {
+ return F->getKind() == MCFragment::FT_Org;
+ }
+ static bool classof(const MCOrgFragment *) { return true; }
};
// FIXME: Should this be a separate class, or just merged into MCSection? Since
@@ -38,6 +245,9 @@
public:
typedef iplist<MCFragment> FragmentListType;
+ typedef FragmentListType::const_iterator const_iterator;
+ typedef FragmentListType::iterator iterator;
+
private:
iplist<MCFragment> Fragments;
const MCSection &Section;
@@ -50,10 +260,12 @@
//
// FIXME: This could all be kept private to the assembler implementation.
- /// FileOffset - The offset of this section in the object file.
+ /// FileOffset - The offset of this section in the object file. This is ~0
+ /// until initialized.
uint64_t FileOffset;
- /// FileSize - The size of this section in the object file.
+ /// FileSize - The size of this section in the object file. This is ~0 until
+ /// initialized.
uint64_t FileSize;
/// @}
@@ -63,26 +275,44 @@
MCSectionData();
MCSectionData(const MCSection &Section, MCAssembler *A = 0);
- const FragmentListType &getFragmentList() const { return Fragments; }
- FragmentListType &getFragmentList() { return Fragments; }
-
const MCSection &getSection() const { return Section; }
unsigned getAlignment() const { return Alignment; }
void setAlignment(unsigned Value) { Alignment = Value; }
+
+ /// @name Section List Access
+ /// @{
+
+ const FragmentListType &getFragmentList() const { return Fragments; }
+ FragmentListType &getFragmentList() { return Fragments; }
+
+ iterator begin() { return Fragments.begin(); }
+ const_iterator begin() const { return Fragments.begin(); }
+
+ iterator end() { return Fragments.end(); }
+ const_iterator end() const { return Fragments.end(); }
+
+ size_t size() const { return Fragments.size(); }
+
+ /// @}
/// @name Assembler Backend Support
/// @{
//
// FIXME: This could all be kept private to the assembler implementation.
- unsigned getFileSize() const { return FileSize; }
-
- uint64_t getFileOffset() const { return FileOffset; }
+ unsigned getFileSize() const {
+ assert(FileSize != ~UINT64_C(0) && "File size not set!");
+ return FileSize;
+ }
+ void setFileSize(uint64_t Value) { FileSize = Value; }
+
+ uint64_t getFileOffset() const {
+ assert(FileOffset != ~UINT64_C(0) && "File offset not set!");
+ return FileOffset;
+ }
void setFileOffset(uint64_t Value) { FileOffset = Value; }
- void WriteFileData(raw_ostream &OS) const;
-
/// @}
};
@@ -101,6 +331,12 @@
iplist<MCSectionData> Sections;
+private:
+ /// LayoutSection - Assign offsets and sizes to the fragments in the section
+ /// \arg SD, and update the section size. The section file offset should
+ /// already have been computed.
+ void LayoutSection(MCSectionData &SD);
+
public:
/// Construct a new assembler instance.
///
Modified: llvm/trunk/lib/MC/MCAssembler.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCAssembler.cpp?rev=79652&r1=79651&r2=79652&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCAssembler.cpp (original)
+++ llvm/trunk/lib/MC/MCAssembler.cpp Fri Aug 21 13:29:01 2009
@@ -10,6 +10,7 @@
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachOWriterInfo.h"
@@ -48,17 +49,37 @@
/// @name Helper Methods
/// @{
+ void Write8(uint8_t Value) {
+ OS << char(Value);
+ }
+
+ void Write16(uint16_t Value) {
+ if (IsLSB) {
+ Write8(uint8_t(Value >> 0));
+ Write8(uint8_t(Value >> 8));
+ } else {
+ Write8(uint8_t(Value >> 8));
+ Write8(uint8_t(Value >> 0));
+ }
+ }
+
void Write32(uint32_t Value) {
if (IsLSB) {
- OS << char(Value >> 0);
- OS << char(Value >> 8);
- OS << char(Value >> 16);
- OS << char(Value >> 24);
+ Write16(uint16_t(Value >> 0));
+ Write16(uint16_t(Value >> 16));
} else {
- OS << char(Value >> 24);
- OS << char(Value >> 16);
- OS << char(Value >> 8);
- OS << char(Value >> 0);
+ Write16(uint16_t(Value >> 16));
+ Write16(uint16_t(Value >> 0));
+ }
+ }
+
+ void Write64(uint64_t Value) {
+ if (IsLSB) {
+ Write32(uint32_t(Value >> 0));
+ Write32(uint32_t(Value >> 32));
+ } else {
+ Write32(uint32_t(Value >> 32));
+ Write32(uint32_t(Value >> 0));
}
}
@@ -115,7 +136,12 @@
Write32(CmdSize);
}
- void WriteSegmentLoadCommand32(unsigned NumSections) {
+ /// WriteSegmentLoadCommand32 - Write a 32-bit segment load command.
+ ///
+ /// \arg NumSections - The number of sections in this segment.
+ /// \arg SectionDataSize - The total size of the sections.
+ void WriteSegmentLoadCommand32(unsigned NumSections,
+ uint64_t SectionDataSize) {
// struct segment_command (56 bytes)
uint64_t Start = OS.tell();
@@ -126,10 +152,10 @@
WriteString("", 16);
Write32(0); // vmaddr
- Write32(0); // vmsize
+ Write32(SectionDataSize); // vmsize
Write32(Header32Size + SegmentLoadCommand32Size +
NumSections * Section32Size); // file offset
- Write32(0); // file size
+ Write32(SectionDataSize); // file size
Write32(0x7); // maxprot
Write32(0x7); // initprot
Write32(NumSections);
@@ -169,12 +195,21 @@
/* *** */
-MCFragment::MCFragment(MCSectionData *SD)
+MCFragment::MCFragment() : Kind(FragmentType(~0)) {
+}
+
+MCFragment::MCFragment(FragmentType _Kind, MCSectionData *SD)
+ : Kind(_Kind),
+ FileOffset(~UINT64_C(0)),
+ FileSize(~UINT64_C(0))
{
if (SD)
SD->getFragmentList().push_back(this);
}
+MCFragment::~MCFragment() {
+}
+
/* *** */
MCSectionData::MCSectionData() : Section(*(MCSection*)0) {}
@@ -182,17 +217,13 @@
MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A)
: Section(_Section),
Alignment(1),
- FileOffset(0),
- FileSize(0)
+ FileOffset(~UINT64_C(0)),
+ FileSize(~UINT64_C(0))
{
if (A)
A->getSectionList().push_back(this);
}
-void MCSectionData::WriteFileData(raw_ostream &OS) const {
-
-}
-
/* *** */
MCAssembler::MCAssembler(raw_ostream &_OS) : OS(_OS) {}
@@ -200,21 +231,97 @@
MCAssembler::~MCAssembler() {
}
+void MCAssembler::LayoutSection(MCSectionData &SD) {
+ uint64_t Offset = SD.getFileOffset();
+
+ for (MCSectionData::iterator it = SD.begin(), ie = SD.end(); it != ie; ++it) {
+ MCFragment &F = *it;
+ F.setFileOffset(Offset);
+ F.setFileSize(F.getMaxFileSize());
+ Offset += F.getFileSize();
+ }
+
+ // FIXME: Pad section?
+ SD.setFileSize(Offset - SD.getFileOffset());
+}
+
+/// WriteFileData - Write the \arg F data to the output file.
+static void WriteFileData(raw_ostream &OS, const MCFragment &F,
+ MachObjectWriter &MOW) {
+ uint64_t Start = OS.tell();
+ (void) Start;
+
+ // FIXME: Embed in fragments instead?
+ switch (F.getKind()) {
+ default:
+ assert(0 && "Invalid section kind!");
+
+ case MCFragment::FT_Data:
+ OS << cast<MCDataFragment>(F).getContents().str();
+ break;
+
+ case MCFragment::FT_Align:
+ llvm_unreachable("FIXME: Not yet implemented!");
+
+ case MCFragment::FT_Fill: {
+ MCFillFragment &FF = cast<MCFillFragment>(F);
+
+ if (!FF.getValue().isAbsolute())
+ llvm_unreachable("FIXME: Not yet implemented!");
+
+ for (uint64_t i = 0, e = FF.getCount(); i != e; ++i) {
+ switch (FF.getValueSize()) {
+ default:
+ assert(0 && "Invalid size!");
+ case 1: MOW.Write8 (uint8_t (FF.getValue().getConstant())); break;
+ case 2: MOW.Write16(uint16_t(FF.getValue().getConstant())); break;
+ case 4: MOW.Write32(uint32_t(FF.getValue().getConstant())); break;
+ case 8: MOW.Write64(uint64_t(FF.getValue().getConstant())); break;
+ }
+ }
+ break;
+ }
+
+ case MCFragment::FT_Org:
+ llvm_unreachable("FIXME: Not yet implemented!");
+ }
+
+ assert(OS.tell() - Start == F.getFileSize());
+}
+
+/// WriteFileData - Write the \arg SD data to the output file.
+static void WriteFileData(raw_ostream &OS, const MCSectionData &SD,
+ MachObjectWriter &MOW) {
+ uint64_t Start = OS.tell();
+ (void) Start;
+
+ for (MCSectionData::const_iterator it = SD.begin(),
+ ie = SD.end(); it != ie; ++it)
+ WriteFileData(OS, *it, MOW);
+
+ assert(OS.tell() - Start == SD.getFileSize());
+}
+
void MCAssembler::Finish() {
unsigned NumSections = Sections.size();
-
- // Compute the file offsets so we can write in a single pass.
+
+ // Layout the sections and fragments.
uint64_t Offset = MachObjectWriter::getPrologSize32(NumSections);
+ uint64_t SectionDataSize = 0;
for (iterator it = begin(), ie = end(); it != ie; ++it) {
it->setFileOffset(Offset);
+
+ LayoutSection(*it);
+
Offset += it->getFileSize();
+ SectionDataSize += it->getFileSize();
}
MachObjectWriter MOW(OS);
// Write the prolog, starting with the header and load command...
MOW.WriteHeader32(NumSections);
- MOW.WriteSegmentLoadCommand32(NumSections);
+ MOW.WriteSegmentLoadCommand32(NumSections, SectionDataSize);
// ... and then the section headers.
for (iterator it = begin(), ie = end(); it != ie; ++it)
@@ -222,7 +329,7 @@
// Finally, write the section data.
for (iterator it = begin(), ie = end(); it != ie; ++it)
- it->WriteFileData(OS);
-
+ WriteFileData(OS, *it, MOW);
+
OS.flush();
}
Modified: llvm/trunk/lib/MC/MCMachOStreamer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCMachOStreamer.cpp?rev=79652&r1=79651&r2=79652&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCMachOStreamer.cpp (original)
+++ llvm/trunk/lib/MC/MCMachOStreamer.cpp Fri Aug 21 13:29:01 2009
@@ -139,22 +139,28 @@
}
void MCMachOStreamer::EmitBytes(const StringRef &Data) {
- llvm_unreachable("FIXME: Not yet implemented!");
+ MCDataFragment *DF = new MCDataFragment(CurSectionData);
+ DF->getContents().append(Data.begin(), Data.end());
}
void MCMachOStreamer::EmitValue(const MCValue &Value, unsigned Size) {
- llvm_unreachable("FIXME: Not yet implemented!");
+ new MCFillFragment(Value, Size, 1, CurSectionData);
}
void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment,
int64_t Value, unsigned ValueSize,
unsigned MaxBytesToEmit) {
- llvm_unreachable("FIXME: Not yet implemented!");
+ new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit,
+ CurSectionData);
+
+ // Update the maximum alignment on the current section if necessary
+ if (ByteAlignment > CurSectionData->getAlignment())
+ CurSectionData->setAlignment(ByteAlignment);
}
void MCMachOStreamer::EmitValueToOffset(const MCValue &Offset,
unsigned char Value) {
- llvm_unreachable("FIXME: Not yet implemented!");
+ new MCOrgFragment(Offset, Value, 1, CurSectionData);
}
void MCMachOStreamer::EmitInstruction(const MCInst &Inst) {
Added: llvm/trunk/test/MC/MachO/data.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/MachO/data.s?rev=79652&view=auto
==============================================================================
--- llvm/trunk/test/MC/MachO/data.s (added)
+++ llvm/trunk/test/MC/MachO/data.s Fri Aug 21 13:29:01 2009
@@ -0,0 +1,60 @@
+// RUN: llvm-mc %s -filetype=obj -o - | macho-dump | FileCheck %s
+
+ .data
+ .ascii "hello"
+ .byte 0xAB
+ .short 0xABCD
+ .long 0xABCDABCD
+ .quad 0xABCDABCDABCDABCD
+
+// CHECK: ('cputype', 7)
+// CHECK: ('cpusubtype', 3)
+// CHECK: ('filetype', 1)
+// CHECK: ('num_load_commands', 1)
+// CHECK: ('load_commands_size', 192)
+// CHECK: ('flag', 0)
+// CHECK: ('load_commands', [
+// CHECK: # Load Command 0
+// CHECK: (('command', 1)
+// CHECK: ('size', 192)
+// CHECK: ('segment_name', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK: ('vm_addr', 0)
+// CHECK: ('vm_size', 20)
+// CHECK: ('file_offset', 220)
+// CHECK: ('file_size', 20)
+// CHECK: ('maxprot', 7)
+// CHECK: ('initprot', 7)
+// CHECK: ('num_sections', 2)
+// CHECK: ('flags', 0)
+// CHECK: ('sections', [
+// CHECK: # Section 0
+// CHECK: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK: ('address', 0)
+// CHECK: ('size', 0)
+// CHECK: ('offset', 220)
+// CHECK: ('alignment', 0)
+// CHECK: ('reloc_offset', 0)
+// CHECK: ('num_reloc', 0)
+// CHECK: ('flags', 0x80000000)
+// CHECK: ('reserved1', 0)
+// CHECK: ('reserved2', 0)
+// CHECK: ),
+// CHECK: # Section 1
+// CHECK: (('section_name', '__data\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK: ('address', 0)
+// CHECK: ('size', 20)
+// CHECK: ('offset', 220)
+// CHECK: ('alignment', 0)
+// CHECK: ('reloc_offset', 0)
+// CHECK: ('num_reloc', 0)
+// CHECK: ('flags', 0x0)
+// CHECK: ('reserved1', 0)
+// CHECK: ('reserved2', 0)
+// CHECK: ),
+// CHECK: ])
+// CHECK: ),
+// CHECK: ])
+
+// FIXME: Dump contents, so we can check those too.
More information about the llvm-commits
mailing list