llvm-mc: Start MCAssembler and MCMachOStreamer.
[oota-llvm.git] / lib / MC / MCAssembler.cpp
1 //===- lib/MC/MCAssembler.cpp - Assembler Backend Implementation ----------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "llvm/MC/MCAssembler.h"
11 #include "llvm/MC/MCSectionMachO.h"
12 #include "llvm/Support/DataTypes.h"
13 #include "llvm/Support/raw_ostream.h"
14 #include "llvm/Target/TargetMachOWriterInfo.h"
15
16 using namespace llvm;
17
18 namespace {
19
20 class MachObjectWriter {
21   // See <mach-o/loader.h>.
22   enum {
23     Header_Magic32 = 0xFEEDFACE,
24     Header_Magic64 = 0xFEEDFACF
25   };
26   
27   static const unsigned Header32Size = 28;
28   static const unsigned Header64Size = 32;
29   static const unsigned SegmentLoadCommand32Size = 56;
30   static const unsigned Section32Size = 68;
31
32   enum HeaderFileType {
33     HFT_Object = 0x1
34   };
35
36   enum LoadCommandType {
37     LCT_Segment = 0x1
38   };
39
40   raw_ostream &OS;
41   bool IsLSB;
42
43 public:
44   MachObjectWriter(raw_ostream &_OS, bool _IsLSB = true) 
45     : OS(_OS), IsLSB(_IsLSB) {
46   }
47
48   /// @name Helper Methods
49   /// @{
50
51   void Write32(uint32_t Value) {
52     if (IsLSB) {
53       OS << char(Value >> 0);
54       OS << char(Value >> 8);
55       OS << char(Value >> 16);
56       OS << char(Value >> 24);
57     } else {
58       OS << char(Value >> 24);
59       OS << char(Value >> 16);
60       OS << char(Value >> 8);
61       OS << char(Value >> 0);
62     }
63   }
64
65   void WriteZeros(unsigned N) {
66     const char Zeros[16] = { 0 };
67     
68     for (unsigned i = 0, e = N / 16; i != e; ++i)
69       OS << StringRef(Zeros, 16);
70     
71     OS << StringRef(Zeros, N % 16);
72   }
73
74   void WriteString(const StringRef &Str, unsigned ZeroFillSize = 0) {
75     OS << Str;
76     if (ZeroFillSize)
77       WriteZeros(ZeroFillSize - Str.size());
78   }
79
80   /// @}
81   
82   static unsigned getPrologSize32(unsigned NumSections) {
83     return Header32Size + SegmentLoadCommand32Size + 
84       NumSections * Section32Size;
85   }
86
87   void WriteHeader32(unsigned NumSections) {
88     // struct mach_header (28 bytes)
89
90     uint64_t Start = OS.tell();
91     (void) Start;
92
93     Write32(Header_Magic32);
94
95     // FIXME: Support cputype.
96     Write32(TargetMachOWriterInfo::HDR_CPU_TYPE_I386);
97
98     // FIXME: Support cpusubtype.
99     Write32(TargetMachOWriterInfo::HDR_CPU_SUBTYPE_I386_ALL);
100
101     Write32(HFT_Object);
102
103     // Object files have a single load command, the segment.
104     Write32(1);
105     Write32(SegmentLoadCommand32Size + NumSections * Section32Size);
106     Write32(0); // Flags
107
108     assert(OS.tell() - Start == Header32Size);
109   }
110
111   void WriteLoadCommandHeader(uint32_t Cmd, uint32_t CmdSize) {
112     assert((CmdSize & 0x3) == 0 && "Invalid size!");
113
114     Write32(Cmd);
115     Write32(CmdSize);
116   }
117
118   void WriteSegmentLoadCommand32(unsigned NumSections) {
119     // struct segment_command (56 bytes)
120
121     uint64_t Start = OS.tell();
122     (void) Start;
123
124     Write32(LCT_Segment);
125     Write32(SegmentLoadCommand32Size + NumSections * Section32Size);
126
127     WriteString("", 16);
128     Write32(0); // vmaddr
129     Write32(0); // vmsize
130     Write32(Header32Size + SegmentLoadCommand32Size + 
131             NumSections * Section32Size); // file offset
132     Write32(0); // file size
133     Write32(0x7); // maxprot
134     Write32(0x7); // initprot
135     Write32(NumSections);
136     Write32(0); // flags
137
138     assert(OS.tell() - Start == SegmentLoadCommand32Size);
139   }
140
141   void WriteSection32(const MCSectionData &SD) {
142     // struct section (68 bytes)
143
144     uint64_t Start = OS.tell();
145     (void) Start;
146
147     // FIXME: cast<> support!
148     const MCSectionMachO &Section =
149       static_cast<const MCSectionMachO&>(SD.getSection());
150     WriteString(Section.getSectionName(), 16);
151     WriteString(Section.getSegmentName(), 16);
152     Write32(0); // address
153     Write32(SD.getFileSize()); // size
154     Write32(SD.getFileOffset());
155
156     assert(isPowerOf2_32(SD.getAlignment()) && "Invalid alignment!");
157     Write32(Log2_32(SD.getAlignment()));
158     Write32(0); // file offset of relocation entries
159     Write32(0); // number of relocation entrions
160     Write32(Section.getTypeAndAttributes());
161     Write32(0); // reserved1
162     Write32(Section.getStubSize()); // reserved2
163
164     assert(OS.tell() - Start == Section32Size);
165   }
166 };
167
168 }
169
170 /* *** */
171
172 MCFragment::MCFragment(MCSectionData *SD)
173 {
174   if (SD)
175     SD->getFragmentList().push_back(this);
176 }
177
178 /* *** */
179
180 MCSectionData::MCSectionData() : Section(*(MCSection*)0) {}
181
182 MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A)
183   : Section(_Section),
184     Alignment(1),
185     FileOffset(0),
186     FileSize(0)
187 {
188   if (A)
189     A->getSectionList().push_back(this);
190 }
191
192 void MCSectionData::WriteFileData(raw_ostream &OS) const {
193   
194 }
195
196 /* *** */
197
198 MCAssembler::MCAssembler(raw_ostream &_OS) : OS(_OS) {}
199
200 MCAssembler::~MCAssembler() {
201 }
202
203 void MCAssembler::Finish() {
204   unsigned NumSections = Sections.size();
205   
206   // Compute the file offsets so we can write in a single pass.
207   uint64_t Offset = MachObjectWriter::getPrologSize32(NumSections);
208   for (iterator it = begin(), ie = end(); it != ie; ++it) {
209     it->setFileOffset(Offset);
210     Offset += it->getFileSize();
211   }
212
213   MachObjectWriter MOW(OS);
214
215   // Write the prolog, starting with the header and load command...
216   MOW.WriteHeader32(NumSections);
217   MOW.WriteSegmentLoadCommand32(NumSections);
218   
219   // ... and then the section headers.
220   for (iterator it = begin(), ie = end(); it != ie; ++it)
221     MOW.WriteSection32(*it);
222
223   // Finally, write the section data.
224   for (iterator it = begin(), ie = end(); it != ie; ++it)
225     it->WriteFileData(OS);
226   
227   OS.flush();
228 }