llvm-mc/Mach-O: Support byte and fill value emission.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79652 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Daniel Dunbar 2009-08-21 18:29:01 +00:00
parent 7178010a16
commit 0705fbf52f
4 changed files with 446 additions and 37 deletions

View File

@ -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 @@ class MCFragment : public ilist_node<MCFragment> {
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 @@ class MCSectionData : public ilist_node<MCSectionData> {
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 @@ private:
//
// 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 @@ public:
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; }
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 { return FileOffset; }
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 @@ private:
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.
///

View File

@ -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 @@ public:
/// @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 @@ public:
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 @@ public:
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 @@ public:
/* *** */
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() : Section(*(MCSection*)0) {}
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(raw_ostream &_OS) : OS(_OS) {}
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 @@ void MCAssembler::Finish() {
// Finally, write the section data.
for (iterator it = begin(), ie = end(); it != ie; ++it)
it->WriteFileData(OS);
WriteFileData(OS, *it, MOW);
OS.flush();
}

View File

@ -139,22 +139,28 @@ void MCMachOStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol,
}
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) {

60
test/MC/MachO/data.s Normal file
View File

@ -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.