llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
//===- lib/MC/MCAssembler.cpp - Assembler Backend Implementation ----------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-08-25 21:10:45 +00:00
|
|
|
#define DEBUG_TYPE "assembler"
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
#include "llvm/MC/MCAssembler.h"
|
2009-08-22 19:19:12 +00:00
|
|
|
#include "llvm/MC/MCSectionMachO.h"
|
|
|
|
#include "llvm/Target/TargetMachOWriterInfo.h"
|
2009-08-22 11:41:10 +00:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2009-08-22 10:13:24 +00:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2009-08-25 21:10:45 +00:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
2009-08-22 10:13:24 +00:00
|
|
|
#include "llvm/ADT/StringMap.h"
|
2009-08-21 23:07:38 +00:00
|
|
|
#include "llvm/ADT/Twine.h"
|
2009-08-21 18:29:01 +00:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2009-08-24 03:52:50 +00:00
|
|
|
#include <vector>
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
using namespace llvm;
|
|
|
|
|
2009-08-22 10:13:24 +00:00
|
|
|
class MachObjectWriter;
|
|
|
|
|
2009-08-25 21:10:45 +00:00
|
|
|
STATISTIC(EmittedFragments, "Number of emitted assembler fragments");
|
|
|
|
|
2009-08-22 10:13:24 +00:00
|
|
|
static void WriteFileData(raw_ostream &OS, const MCSectionData &SD,
|
|
|
|
MachObjectWriter &MOW);
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
|
|
|
|
class MachObjectWriter {
|
|
|
|
// See <mach-o/loader.h>.
|
|
|
|
enum {
|
|
|
|
Header_Magic32 = 0xFEEDFACE,
|
|
|
|
Header_Magic64 = 0xFEEDFACF
|
|
|
|
};
|
|
|
|
|
|
|
|
static const unsigned Header32Size = 28;
|
|
|
|
static const unsigned Header64Size = 32;
|
|
|
|
static const unsigned SegmentLoadCommand32Size = 56;
|
|
|
|
static const unsigned Section32Size = 68;
|
2009-08-22 10:13:24 +00:00
|
|
|
static const unsigned SymtabLoadCommandSize = 24;
|
|
|
|
static const unsigned DysymtabLoadCommandSize = 80;
|
|
|
|
static const unsigned Nlist32Size = 12;
|
2009-08-26 13:58:10 +00:00
|
|
|
static const unsigned RelocationInfoSize = 8;
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
|
|
|
|
enum HeaderFileType {
|
|
|
|
HFT_Object = 0x1
|
|
|
|
};
|
|
|
|
|
2009-08-26 21:22:22 +00:00
|
|
|
enum HeaderFlags {
|
|
|
|
HF_SubsectionsViaSymbols = 0x2000
|
|
|
|
};
|
|
|
|
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
enum LoadCommandType {
|
2009-08-22 10:13:24 +00:00
|
|
|
LCT_Segment = 0x1,
|
|
|
|
LCT_Symtab = 0x2,
|
|
|
|
LCT_Dysymtab = 0xb
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
};
|
|
|
|
|
2009-08-22 11:41:10 +00:00
|
|
|
// See <mach-o/nlist.h>.
|
|
|
|
enum SymbolTypeType {
|
|
|
|
STT_Undefined = 0x00,
|
|
|
|
STT_Absolute = 0x02,
|
|
|
|
STT_Section = 0x0e
|
|
|
|
};
|
|
|
|
|
|
|
|
enum SymbolTypeFlags {
|
|
|
|
// If any of these bits are set, then the entry is a stab entry number (see
|
|
|
|
// <mach-o/stab.h>. Otherwise the other masks apply.
|
|
|
|
STF_StabsEntryMask = 0xe0,
|
|
|
|
|
|
|
|
STF_TypeMask = 0x0e,
|
|
|
|
STF_External = 0x01,
|
|
|
|
STF_PrivateExtern = 0x10
|
|
|
|
};
|
|
|
|
|
2009-08-26 00:18:21 +00:00
|
|
|
/// IndirectSymbolFlags - Flags for encoding special values in the indirect
|
|
|
|
/// symbol entry.
|
|
|
|
enum IndirectSymbolFlags {
|
|
|
|
ISF_Local = 0x80000000,
|
|
|
|
ISF_Absolute = 0x40000000
|
|
|
|
};
|
|
|
|
|
2009-08-26 13:58:10 +00:00
|
|
|
/// RelocationFlags - Special flags for addresses.
|
|
|
|
enum RelocationFlags {
|
|
|
|
RF_Scattered = 0x80000000
|
|
|
|
};
|
|
|
|
|
|
|
|
enum RelocationInfoType {
|
|
|
|
RIT_Vanilla = 0,
|
|
|
|
RIT_Pair = 1,
|
|
|
|
RIT_Difference = 2,
|
|
|
|
RIT_PreboundLazyPointer = 3,
|
|
|
|
RIT_LocalDifference = 4
|
|
|
|
};
|
|
|
|
|
2009-08-22 11:41:10 +00:00
|
|
|
/// MachSymbolData - Helper struct for containing some precomputed information
|
|
|
|
/// on symbols.
|
|
|
|
struct MachSymbolData {
|
|
|
|
MCSymbolData *SymbolData;
|
|
|
|
uint64_t StringIndex;
|
|
|
|
uint8_t SectionIndex;
|
|
|
|
|
|
|
|
// Support lexicographic sorting.
|
|
|
|
bool operator<(const MachSymbolData &RHS) const {
|
|
|
|
const std::string &Name = SymbolData->getSymbol().getName();
|
|
|
|
return Name < RHS.SymbolData->getSymbol().getName();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
raw_ostream &OS;
|
|
|
|
bool IsLSB;
|
|
|
|
|
|
|
|
public:
|
|
|
|
MachObjectWriter(raw_ostream &_OS, bool _IsLSB = true)
|
|
|
|
: OS(_OS), IsLSB(_IsLSB) {
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @name Helper Methods
|
|
|
|
/// @{
|
|
|
|
|
2009-08-21 18:29:01 +00:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
void Write32(uint32_t Value) {
|
|
|
|
if (IsLSB) {
|
2009-08-21 18:29:01 +00:00
|
|
|
Write16(uint16_t(Value >> 0));
|
|
|
|
Write16(uint16_t(Value >> 16));
|
|
|
|
} else {
|
|
|
|
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));
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
} else {
|
2009-08-21 18:29:01 +00:00
|
|
|
Write32(uint32_t(Value >> 32));
|
|
|
|
Write32(uint32_t(Value >> 0));
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void WriteZeros(unsigned N) {
|
|
|
|
const char Zeros[16] = { 0 };
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = N / 16; i != e; ++i)
|
|
|
|
OS << StringRef(Zeros, 16);
|
|
|
|
|
|
|
|
OS << StringRef(Zeros, N % 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WriteString(const StringRef &Str, unsigned ZeroFillSize = 0) {
|
|
|
|
OS << Str;
|
|
|
|
if (ZeroFillSize)
|
|
|
|
WriteZeros(ZeroFillSize - Str.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @}
|
|
|
|
|
2009-08-26 21:22:22 +00:00
|
|
|
void WriteHeader32(unsigned NumLoadCommands, unsigned LoadCommandsSize,
|
|
|
|
bool SubsectionsViaSymbols) {
|
|
|
|
uint32_t Flags = 0;
|
|
|
|
|
|
|
|
if (SubsectionsViaSymbols)
|
|
|
|
Flags |= HF_SubsectionsViaSymbols;
|
|
|
|
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
// struct mach_header (28 bytes)
|
|
|
|
|
|
|
|
uint64_t Start = OS.tell();
|
|
|
|
(void) Start;
|
|
|
|
|
|
|
|
Write32(Header_Magic32);
|
|
|
|
|
|
|
|
// FIXME: Support cputype.
|
|
|
|
Write32(TargetMachOWriterInfo::HDR_CPU_TYPE_I386);
|
|
|
|
// FIXME: Support cpusubtype.
|
|
|
|
Write32(TargetMachOWriterInfo::HDR_CPU_SUBTYPE_I386_ALL);
|
|
|
|
Write32(HFT_Object);
|
2009-08-26 21:22:22 +00:00
|
|
|
Write32(NumLoadCommands); // Object files have a single load command, the
|
|
|
|
// segment.
|
2009-08-22 10:13:24 +00:00
|
|
|
Write32(LoadCommandsSize);
|
2009-08-26 21:22:22 +00:00
|
|
|
Write32(Flags);
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
|
|
|
|
assert(OS.tell() - Start == Header32Size);
|
|
|
|
}
|
|
|
|
|
2009-08-21 18:29:01 +00:00
|
|
|
/// 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,
|
2009-08-22 10:13:24 +00:00
|
|
|
uint64_t SectionDataStartOffset,
|
2009-08-21 18:29:01 +00:00
|
|
|
uint64_t SectionDataSize) {
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
// struct segment_command (56 bytes)
|
|
|
|
|
|
|
|
uint64_t Start = OS.tell();
|
|
|
|
(void) Start;
|
|
|
|
|
|
|
|
Write32(LCT_Segment);
|
|
|
|
Write32(SegmentLoadCommand32Size + NumSections * Section32Size);
|
|
|
|
|
|
|
|
WriteString("", 16);
|
|
|
|
Write32(0); // vmaddr
|
2009-08-21 18:29:01 +00:00
|
|
|
Write32(SectionDataSize); // vmsize
|
2009-08-22 10:13:24 +00:00
|
|
|
Write32(SectionDataStartOffset); // file offset
|
2009-08-21 18:29:01 +00:00
|
|
|
Write32(SectionDataSize); // file size
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
Write32(0x7); // maxprot
|
|
|
|
Write32(0x7); // initprot
|
|
|
|
Write32(NumSections);
|
|
|
|
Write32(0); // flags
|
|
|
|
|
|
|
|
assert(OS.tell() - Start == SegmentLoadCommand32Size);
|
|
|
|
}
|
|
|
|
|
2009-08-26 13:58:10 +00:00
|
|
|
void WriteSection32(const MCSectionData &SD, uint64_t FileOffset,
|
|
|
|
uint64_t RelocationsStart, unsigned NumRelocations) {
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
// struct section (68 bytes)
|
|
|
|
|
|
|
|
uint64_t Start = OS.tell();
|
|
|
|
(void) Start;
|
|
|
|
|
|
|
|
// FIXME: cast<> support!
|
|
|
|
const MCSectionMachO &Section =
|
|
|
|
static_cast<const MCSectionMachO&>(SD.getSection());
|
|
|
|
WriteString(Section.getSectionName(), 16);
|
|
|
|
WriteString(Section.getSegmentName(), 16);
|
2009-08-26 02:48:04 +00:00
|
|
|
Write32(SD.getAddress()); // address
|
2009-08-26 04:13:32 +00:00
|
|
|
Write32(SD.getSize()); // size
|
2009-08-22 08:28:27 +00:00
|
|
|
Write32(FileOffset);
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
|
|
|
|
assert(isPowerOf2_32(SD.getAlignment()) && "Invalid alignment!");
|
|
|
|
Write32(Log2_32(SD.getAlignment()));
|
2009-08-26 13:58:10 +00:00
|
|
|
Write32(NumRelocations ? RelocationsStart : 0);
|
|
|
|
Write32(NumRelocations);
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
Write32(Section.getTypeAndAttributes());
|
|
|
|
Write32(0); // reserved1
|
|
|
|
Write32(Section.getStubSize()); // reserved2
|
|
|
|
|
|
|
|
assert(OS.tell() - Start == Section32Size);
|
|
|
|
}
|
2009-08-22 08:28:27 +00:00
|
|
|
|
2009-08-22 10:13:24 +00:00
|
|
|
void WriteSymtabLoadCommand(uint32_t SymbolOffset, uint32_t NumSymbols,
|
|
|
|
uint32_t StringTableOffset,
|
|
|
|
uint32_t StringTableSize) {
|
|
|
|
// struct symtab_command (24 bytes)
|
|
|
|
|
|
|
|
uint64_t Start = OS.tell();
|
|
|
|
(void) Start;
|
|
|
|
|
|
|
|
Write32(LCT_Symtab);
|
|
|
|
Write32(SymtabLoadCommandSize);
|
|
|
|
Write32(SymbolOffset);
|
|
|
|
Write32(NumSymbols);
|
|
|
|
Write32(StringTableOffset);
|
|
|
|
Write32(StringTableSize);
|
|
|
|
|
|
|
|
assert(OS.tell() - Start == SymtabLoadCommandSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WriteDysymtabLoadCommand(uint32_t FirstLocalSymbol,
|
|
|
|
uint32_t NumLocalSymbols,
|
|
|
|
uint32_t FirstExternalSymbol,
|
|
|
|
uint32_t NumExternalSymbols,
|
|
|
|
uint32_t FirstUndefinedSymbol,
|
|
|
|
uint32_t NumUndefinedSymbols,
|
|
|
|
uint32_t IndirectSymbolOffset,
|
|
|
|
uint32_t NumIndirectSymbols) {
|
|
|
|
// struct dysymtab_command (80 bytes)
|
|
|
|
|
|
|
|
uint64_t Start = OS.tell();
|
|
|
|
(void) Start;
|
|
|
|
|
|
|
|
Write32(LCT_Dysymtab);
|
|
|
|
Write32(DysymtabLoadCommandSize);
|
|
|
|
Write32(FirstLocalSymbol);
|
|
|
|
Write32(NumLocalSymbols);
|
|
|
|
Write32(FirstExternalSymbol);
|
|
|
|
Write32(NumExternalSymbols);
|
|
|
|
Write32(FirstUndefinedSymbol);
|
|
|
|
Write32(NumUndefinedSymbols);
|
|
|
|
Write32(0); // tocoff
|
|
|
|
Write32(0); // ntoc
|
|
|
|
Write32(0); // modtaboff
|
|
|
|
Write32(0); // nmodtab
|
|
|
|
Write32(0); // extrefsymoff
|
|
|
|
Write32(0); // nextrefsyms
|
|
|
|
Write32(IndirectSymbolOffset);
|
|
|
|
Write32(NumIndirectSymbols);
|
|
|
|
Write32(0); // extreloff
|
|
|
|
Write32(0); // nextrel
|
|
|
|
Write32(0); // locreloff
|
|
|
|
Write32(0); // nlocrel
|
|
|
|
|
|
|
|
assert(OS.tell() - Start == DysymtabLoadCommandSize);
|
|
|
|
}
|
|
|
|
|
2009-08-22 11:41:10 +00:00
|
|
|
void WriteNlist32(MachSymbolData &MSD) {
|
2009-08-26 02:48:04 +00:00
|
|
|
MCSymbolData &Data = *MSD.SymbolData;
|
|
|
|
MCSymbol &Symbol = Data.getSymbol();
|
2009-08-22 11:41:10 +00:00
|
|
|
uint8_t Type = 0;
|
|
|
|
|
|
|
|
// Set the N_TYPE bits. See <mach-o/nlist.h>.
|
|
|
|
//
|
|
|
|
// FIXME: Are the prebound or indirect fields possible here?
|
|
|
|
if (Symbol.isUndefined())
|
|
|
|
Type = STT_Undefined;
|
|
|
|
else if (Symbol.isAbsolute())
|
|
|
|
Type = STT_Absolute;
|
|
|
|
else
|
|
|
|
Type = STT_Section;
|
|
|
|
|
|
|
|
// FIXME: Set STAB bits.
|
|
|
|
|
2009-08-26 02:48:04 +00:00
|
|
|
if (Data.isPrivateExtern())
|
2009-08-24 08:40:12 +00:00
|
|
|
Type |= STF_PrivateExtern;
|
2009-08-22 11:41:10 +00:00
|
|
|
|
|
|
|
// Set external bit.
|
2009-08-26 02:48:04 +00:00
|
|
|
if (Data.isExternal() || Symbol.isUndefined())
|
2009-08-22 11:41:10 +00:00
|
|
|
Type |= STF_External;
|
|
|
|
|
2009-08-22 10:13:24 +00:00
|
|
|
// struct nlist (12 bytes)
|
|
|
|
|
2009-08-22 11:41:10 +00:00
|
|
|
Write32(MSD.StringIndex);
|
2009-08-22 10:13:24 +00:00
|
|
|
Write8(Type);
|
2009-08-22 11:41:10 +00:00
|
|
|
Write8(MSD.SectionIndex);
|
2009-08-24 08:40:12 +00:00
|
|
|
|
|
|
|
// The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc'
|
|
|
|
// value.
|
2009-08-26 02:48:04 +00:00
|
|
|
Write16(Data.getFlags() & 0xFFFF);
|
2009-08-24 08:40:12 +00:00
|
|
|
|
2009-08-26 02:48:04 +00:00
|
|
|
// Write the symbol address.
|
|
|
|
uint32_t Address = 0;
|
|
|
|
if (Symbol.isDefined()) {
|
|
|
|
if (Symbol.isAbsolute()) {
|
|
|
|
llvm_unreachable("FIXME: Not yet implemented!");
|
|
|
|
} else {
|
|
|
|
Address = Data.getFragment()->getAddress() + Data.getOffset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Write32(Address);
|
2009-08-22 10:13:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-26 13:58:10 +00:00
|
|
|
struct MachRelocationEntry {
|
|
|
|
uint32_t Word0;
|
|
|
|
uint32_t Word1;
|
|
|
|
};
|
|
|
|
void ComputeScatteredRelocationInfo(MCAssembler &Asm,
|
|
|
|
MCSectionData::Fixup &Fixup,
|
|
|
|
DenseMap<const MCSymbol*,MCSymbolData*> &SymbolMap,
|
|
|
|
std::vector<MachRelocationEntry> &Relocs) {
|
|
|
|
uint32_t Address = Fixup.Fragment->getOffset() + Fixup.Offset;
|
|
|
|
unsigned IsPCRel = 0;
|
|
|
|
unsigned Type = RIT_Vanilla;
|
|
|
|
|
|
|
|
// See <reloc.h>.
|
|
|
|
|
|
|
|
const MCSymbol *A = Fixup.Value.getSymA();
|
|
|
|
MCSymbolData *SD = SymbolMap.lookup(A);
|
|
|
|
uint32_t Value = SD->getFragment()->getAddress() + SD->getOffset();
|
|
|
|
uint32_t Value2 = 0;
|
|
|
|
|
|
|
|
if (const MCSymbol *B = Fixup.Value.getSymB()) {
|
|
|
|
Type = RIT_LocalDifference;
|
|
|
|
|
|
|
|
MCSymbolData *SD = SymbolMap.lookup(B);
|
|
|
|
Value2 = SD->getFragment()->getAddress() + SD->getOffset();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned Log2Size = Log2_32(Fixup.Size);
|
|
|
|
assert((1U << Log2Size) == Fixup.Size && "Invalid fixup size!");
|
|
|
|
|
|
|
|
// The value which goes in the fixup is current value of the expression.
|
|
|
|
Fixup.FixedValue = Value - Value2 + Fixup.Value.getConstant();
|
|
|
|
|
|
|
|
MachRelocationEntry MRE;
|
|
|
|
MRE.Word0 = ((Address << 0) |
|
|
|
|
(Type << 24) |
|
|
|
|
(Log2Size << 28) |
|
|
|
|
(IsPCRel << 30) |
|
|
|
|
RF_Scattered);
|
|
|
|
MRE.Word1 = Value;
|
|
|
|
Relocs.push_back(MRE);
|
|
|
|
|
|
|
|
if (Type == RIT_LocalDifference) {
|
|
|
|
Type = RIT_Pair;
|
|
|
|
|
|
|
|
MachRelocationEntry MRE;
|
|
|
|
MRE.Word0 = ((0 << 0) |
|
|
|
|
(Type << 24) |
|
|
|
|
(Log2Size << 28) |
|
|
|
|
(0 << 30) |
|
|
|
|
RF_Scattered);
|
|
|
|
MRE.Word1 = Value2;
|
|
|
|
Relocs.push_back(MRE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComputeRelocationInfo(MCAssembler &Asm,
|
|
|
|
MCSectionData::Fixup &Fixup,
|
|
|
|
DenseMap<const MCSymbol*,MCSymbolData*> &SymbolMap,
|
|
|
|
std::vector<MachRelocationEntry> &Relocs) {
|
|
|
|
// If this is a local symbol plus an offset or a difference, then we need a
|
|
|
|
// scattered relocation entry.
|
|
|
|
if (Fixup.Value.getSymB()) // a - b
|
|
|
|
return ComputeScatteredRelocationInfo(Asm, Fixup, SymbolMap, Relocs);
|
|
|
|
if (Fixup.Value.getSymA() && Fixup.Value.getConstant())
|
|
|
|
if (!Fixup.Value.getSymA()->isUndefined())
|
|
|
|
return ComputeScatteredRelocationInfo(Asm, Fixup, SymbolMap, Relocs);
|
|
|
|
|
|
|
|
// See <reloc.h>.
|
|
|
|
uint32_t Address = Fixup.Fragment->getOffset() + Fixup.Offset;
|
|
|
|
uint32_t Value = 0;
|
|
|
|
unsigned Index = 0;
|
|
|
|
unsigned IsPCRel = 0;
|
|
|
|
unsigned IsExtern = 0;
|
|
|
|
unsigned Type = 0;
|
|
|
|
|
|
|
|
if (Fixup.Value.isAbsolute()) { // constant
|
|
|
|
// SymbolNum of 0 indicates the absolute section.
|
|
|
|
Type = RIT_Vanilla;
|
|
|
|
Value = 0;
|
|
|
|
llvm_unreachable("FIXME: Not yet implemented!");
|
|
|
|
} else {
|
|
|
|
const MCSymbol *Symbol = Fixup.Value.getSymA();
|
|
|
|
MCSymbolData *SD = SymbolMap.lookup(Symbol);
|
|
|
|
|
|
|
|
if (Symbol->isUndefined()) {
|
|
|
|
IsExtern = 1;
|
|
|
|
Index = SD->getIndex();
|
|
|
|
Value = 0;
|
|
|
|
} else {
|
|
|
|
// The index is the section ordinal.
|
|
|
|
//
|
|
|
|
// FIXME: O(N)
|
|
|
|
Index = 1;
|
|
|
|
for (MCAssembler::iterator it = Asm.begin(),
|
|
|
|
ie = Asm.end(); it != ie; ++it, ++Index)
|
|
|
|
if (&*it == SD->getFragment()->getParent())
|
|
|
|
break;
|
|
|
|
Value = SD->getFragment()->getAddress() + SD->getOffset();
|
|
|
|
}
|
|
|
|
|
|
|
|
Type = RIT_Vanilla;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The value which goes in the fixup is current value of the expression.
|
|
|
|
Fixup.FixedValue = Value + Fixup.Value.getConstant();
|
|
|
|
|
|
|
|
unsigned Log2Size = Log2_32(Fixup.Size);
|
|
|
|
assert((1U << Log2Size) == Fixup.Size && "Invalid fixup size!");
|
|
|
|
|
|
|
|
// struct relocation_info (8 bytes)
|
|
|
|
MachRelocationEntry MRE;
|
|
|
|
MRE.Word0 = Address;
|
|
|
|
MRE.Word1 = ((Index << 0) |
|
|
|
|
(IsPCRel << 24) |
|
|
|
|
(Log2Size << 25) |
|
|
|
|
(IsExtern << 27) |
|
|
|
|
(Type << 28));
|
|
|
|
Relocs.push_back(MRE);
|
|
|
|
}
|
|
|
|
|
2009-08-26 00:18:21 +00:00
|
|
|
void BindIndirectSymbols(MCAssembler &Asm,
|
2009-08-26 13:57:54 +00:00
|
|
|
DenseMap<const MCSymbol*,MCSymbolData*> &SymbolMap) {
|
2009-08-24 11:56:58 +00:00
|
|
|
// This is the point where 'as' creates actual symbols for indirect symbols
|
|
|
|
// (in the following two passes). It would be easier for us to do this
|
|
|
|
// sooner when we see the attribute, but that makes getting the order in the
|
|
|
|
// symbol table much more complicated than it is worth.
|
|
|
|
//
|
|
|
|
// FIXME: Revisit this when the dust settles.
|
|
|
|
|
|
|
|
// Bind non lazy symbol pointers first.
|
|
|
|
for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(),
|
|
|
|
ie = Asm.indirect_symbol_end(); it != ie; ++it) {
|
|
|
|
// FIXME: cast<> support!
|
|
|
|
const MCSectionMachO &Section =
|
|
|
|
static_cast<const MCSectionMachO&>(it->SectionData->getSection());
|
|
|
|
|
|
|
|
unsigned Type =
|
|
|
|
Section.getTypeAndAttributes() & MCSectionMachO::SECTION_TYPE;
|
|
|
|
if (Type != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
MCSymbolData *&Entry = SymbolMap[it->Symbol];
|
|
|
|
if (!Entry)
|
|
|
|
Entry = new MCSymbolData(*it->Symbol, 0, 0, &Asm);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Then lazy symbol pointers and symbol stubs.
|
|
|
|
for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(),
|
|
|
|
ie = Asm.indirect_symbol_end(); it != ie; ++it) {
|
|
|
|
// FIXME: cast<> support!
|
|
|
|
const MCSectionMachO &Section =
|
|
|
|
static_cast<const MCSectionMachO&>(it->SectionData->getSection());
|
|
|
|
|
|
|
|
unsigned Type =
|
|
|
|
Section.getTypeAndAttributes() & MCSectionMachO::SECTION_TYPE;
|
|
|
|
if (Type != MCSectionMachO::S_LAZY_SYMBOL_POINTERS &&
|
|
|
|
Type != MCSectionMachO::S_SYMBOL_STUBS)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
MCSymbolData *&Entry = SymbolMap[it->Symbol];
|
|
|
|
if (!Entry) {
|
|
|
|
Entry = new MCSymbolData(*it->Symbol, 0, 0, &Asm);
|
|
|
|
|
|
|
|
// Set the symbol type to undefined lazy, but only on construction.
|
|
|
|
//
|
|
|
|
// FIXME: Do not hardcode.
|
|
|
|
Entry->setFlags(Entry->getFlags() | 0x0001);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-22 11:41:10 +00:00
|
|
|
/// ComputeSymbolTable - Compute the symbol table data
|
2009-08-22 10:13:24 +00:00
|
|
|
///
|
|
|
|
/// \param StringTable [out] - The string table data.
|
|
|
|
/// \param StringIndexMap [out] - Map from symbol names to offsets in the
|
|
|
|
/// string table.
|
2009-08-22 11:41:10 +00:00
|
|
|
void ComputeSymbolTable(MCAssembler &Asm, SmallString<256> &StringTable,
|
|
|
|
std::vector<MachSymbolData> &LocalSymbolData,
|
|
|
|
std::vector<MachSymbolData> &ExternalSymbolData,
|
|
|
|
std::vector<MachSymbolData> &UndefinedSymbolData) {
|
|
|
|
// Build section lookup table.
|
|
|
|
DenseMap<const MCSection*, uint8_t> SectionIndexMap;
|
|
|
|
unsigned Index = 1;
|
|
|
|
for (MCAssembler::iterator it = Asm.begin(),
|
|
|
|
ie = Asm.end(); it != ie; ++it, ++Index)
|
|
|
|
SectionIndexMap[&it->getSection()] = Index;
|
|
|
|
assert(Index <= 256 && "Too many sections!");
|
2009-08-22 10:13:24 +00:00
|
|
|
|
|
|
|
// Index 0 is always the empty string.
|
2009-08-22 11:41:10 +00:00
|
|
|
StringMap<uint64_t> StringIndexMap;
|
2009-08-22 10:13:24 +00:00
|
|
|
StringTable += '\x00';
|
2009-08-22 11:41:10 +00:00
|
|
|
|
|
|
|
// Build the symbol arrays and the string table, but only for non-local
|
|
|
|
// symbols.
|
|
|
|
//
|
|
|
|
// The particular order that we collect the symbols and create the string
|
|
|
|
// table, then sort the symbols is chosen to match 'as'. Even though it
|
|
|
|
// doesn't matter for correctness, this is important for letting us diff .o
|
|
|
|
// files.
|
2009-08-22 10:13:24 +00:00
|
|
|
for (MCAssembler::symbol_iterator it = Asm.symbol_begin(),
|
|
|
|
ie = Asm.symbol_end(); it != ie; ++it) {
|
2009-08-22 11:41:10 +00:00
|
|
|
MCSymbol &Symbol = it->getSymbol();
|
|
|
|
|
2009-08-24 08:39:57 +00:00
|
|
|
if (!it->isExternal() && !Symbol.isUndefined())
|
2009-08-22 11:41:10 +00:00
|
|
|
continue;
|
2009-08-22 10:13:24 +00:00
|
|
|
|
2009-08-22 11:41:10 +00:00
|
|
|
uint64_t &Entry = StringIndexMap[Symbol.getName()];
|
2009-08-22 10:13:24 +00:00
|
|
|
if (!Entry) {
|
|
|
|
Entry = StringTable.size();
|
2009-08-22 11:41:10 +00:00
|
|
|
StringTable += Symbol.getName();
|
2009-08-22 10:13:24 +00:00
|
|
|
StringTable += '\x00';
|
|
|
|
}
|
2009-08-22 11:41:10 +00:00
|
|
|
|
|
|
|
MachSymbolData MSD;
|
|
|
|
MSD.SymbolData = it;
|
|
|
|
MSD.StringIndex = Entry;
|
|
|
|
|
|
|
|
if (Symbol.isUndefined()) {
|
|
|
|
MSD.SectionIndex = 0;
|
|
|
|
UndefinedSymbolData.push_back(MSD);
|
|
|
|
} else if (Symbol.isAbsolute()) {
|
|
|
|
MSD.SectionIndex = 0;
|
|
|
|
ExternalSymbolData.push_back(MSD);
|
|
|
|
} else {
|
|
|
|
MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection());
|
|
|
|
assert(MSD.SectionIndex && "Invalid section index!");
|
|
|
|
ExternalSymbolData.push_back(MSD);
|
|
|
|
}
|
2009-08-22 10:13:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-22 11:41:10 +00:00
|
|
|
// Now add the data for local symbols.
|
|
|
|
for (MCAssembler::symbol_iterator it = Asm.symbol_begin(),
|
|
|
|
ie = Asm.symbol_end(); it != ie; ++it) {
|
|
|
|
MCSymbol &Symbol = it->getSymbol();
|
|
|
|
|
2009-08-24 08:39:57 +00:00
|
|
|
if (it->isExternal() || Symbol.isUndefined())
|
2009-08-22 11:41:10 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
uint64_t &Entry = StringIndexMap[Symbol.getName()];
|
|
|
|
if (!Entry) {
|
|
|
|
Entry = StringTable.size();
|
|
|
|
StringTable += Symbol.getName();
|
|
|
|
StringTable += '\x00';
|
|
|
|
}
|
|
|
|
|
|
|
|
MachSymbolData MSD;
|
|
|
|
MSD.SymbolData = it;
|
|
|
|
MSD.StringIndex = Entry;
|
|
|
|
|
|
|
|
if (Symbol.isAbsolute()) {
|
|
|
|
MSD.SectionIndex = 0;
|
|
|
|
LocalSymbolData.push_back(MSD);
|
|
|
|
} else {
|
|
|
|
MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection());
|
|
|
|
assert(MSD.SectionIndex && "Invalid section index!");
|
|
|
|
LocalSymbolData.push_back(MSD);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// External and undefined symbols are required to be in lexicographic order.
|
|
|
|
std::sort(ExternalSymbolData.begin(), ExternalSymbolData.end());
|
|
|
|
std::sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end());
|
|
|
|
|
2009-08-26 13:57:54 +00:00
|
|
|
// Set the symbol indices.
|
|
|
|
Index = 0;
|
|
|
|
for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i)
|
|
|
|
LocalSymbolData[i].SymbolData->setIndex(Index++);
|
|
|
|
for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i)
|
|
|
|
ExternalSymbolData[i].SymbolData->setIndex(Index++);
|
|
|
|
for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i)
|
|
|
|
UndefinedSymbolData[i].SymbolData->setIndex(Index++);
|
|
|
|
|
2009-08-22 10:13:24 +00:00
|
|
|
// The string table is padded to a multiple of 4.
|
|
|
|
//
|
|
|
|
// FIXME: Check to see if this varies per arch.
|
|
|
|
while (StringTable.size() % 4)
|
|
|
|
StringTable += '\x00';
|
|
|
|
}
|
|
|
|
|
|
|
|
void WriteObject(MCAssembler &Asm) {
|
2009-08-22 08:28:27 +00:00
|
|
|
unsigned NumSections = Asm.size();
|
|
|
|
|
2009-08-26 00:18:21 +00:00
|
|
|
// Compute the symbol -> symbol data map.
|
|
|
|
//
|
|
|
|
// FIXME: This should not be here.
|
2009-08-26 13:57:54 +00:00
|
|
|
DenseMap<const MCSymbol*, MCSymbolData *> SymbolMap;
|
2009-08-26 00:18:21 +00:00
|
|
|
for (MCAssembler::symbol_iterator it = Asm.symbol_begin(),
|
|
|
|
ie = Asm.symbol_end(); it != ie; ++it)
|
|
|
|
SymbolMap[&it->getSymbol()] = it;
|
|
|
|
|
|
|
|
// Create symbol data for any indirect symbols.
|
|
|
|
BindIndirectSymbols(Asm, SymbolMap);
|
2009-08-24 11:56:58 +00:00
|
|
|
|
2009-08-22 10:13:24 +00:00
|
|
|
// Compute symbol table information.
|
|
|
|
SmallString<256> StringTable;
|
2009-08-22 11:41:10 +00:00
|
|
|
std::vector<MachSymbolData> LocalSymbolData;
|
|
|
|
std::vector<MachSymbolData> ExternalSymbolData;
|
|
|
|
std::vector<MachSymbolData> UndefinedSymbolData;
|
2009-08-22 10:13:24 +00:00
|
|
|
unsigned NumSymbols = Asm.symbol_size();
|
|
|
|
|
|
|
|
// No symbol table command is written if there are no symbols.
|
|
|
|
if (NumSymbols)
|
2009-08-22 11:41:10 +00:00
|
|
|
ComputeSymbolTable(Asm, StringTable, LocalSymbolData, ExternalSymbolData,
|
|
|
|
UndefinedSymbolData);
|
2009-08-22 08:28:27 +00:00
|
|
|
|
2009-08-22 10:13:24 +00:00
|
|
|
// The section data starts after the header, the segment load command (and
|
|
|
|
// section headers) and the symbol table.
|
|
|
|
unsigned NumLoadCommands = 1;
|
|
|
|
uint64_t LoadCommandsSize =
|
|
|
|
SegmentLoadCommand32Size + NumSections * Section32Size;
|
|
|
|
|
|
|
|
// Add the symbol table load command sizes, if used.
|
|
|
|
if (NumSymbols) {
|
|
|
|
NumLoadCommands += 2;
|
|
|
|
LoadCommandsSize += SymtabLoadCommandSize + DysymtabLoadCommandSize;
|
|
|
|
}
|
|
|
|
|
2009-08-26 04:13:32 +00:00
|
|
|
uint64_t SectionDataStart = Header32Size + LoadCommandsSize;
|
|
|
|
uint64_t SectionDataEnd = SectionDataStart;
|
2009-08-22 08:28:27 +00:00
|
|
|
uint64_t SectionDataSize = 0;
|
2009-08-26 04:13:32 +00:00
|
|
|
if (!Asm.getSectionList().empty()) {
|
|
|
|
MCSectionData &SD = Asm.getSectionList().back();
|
|
|
|
SectionDataSize = SD.getAddress() + SD.getSize();
|
|
|
|
SectionDataEnd = SectionDataStart + SD.getAddress() + SD.getFileSize();
|
2009-08-22 08:28:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Write the prolog, starting with the header and load command...
|
2009-08-26 21:22:22 +00:00
|
|
|
WriteHeader32(NumLoadCommands, LoadCommandsSize,
|
|
|
|
Asm.getSubsectionsViaSymbols());
|
2009-08-26 04:13:32 +00:00
|
|
|
WriteSegmentLoadCommand32(NumSections, SectionDataStart, SectionDataSize);
|
2009-08-22 08:28:27 +00:00
|
|
|
|
|
|
|
// ... and then the section headers.
|
2009-08-26 13:58:10 +00:00
|
|
|
//
|
|
|
|
// We also compute the section relocations while we do this. Note that
|
|
|
|
// compute relocation info will also update the fixup to have the correct
|
|
|
|
// value; this will be overwrite the appropriate data in the fragment when
|
|
|
|
// it is written.
|
|
|
|
std::vector<MachRelocationEntry> RelocInfos;
|
|
|
|
uint64_t RelocTableEnd = SectionDataEnd;
|
|
|
|
for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie;
|
|
|
|
++it) {
|
|
|
|
MCSectionData &SD = *it;
|
|
|
|
|
|
|
|
// The assembler writes relocations in the reverse order they were seen.
|
|
|
|
//
|
|
|
|
// FIXME: It is probably more complicated than this.
|
|
|
|
unsigned NumRelocsStart = RelocInfos.size();
|
|
|
|
for (unsigned i = 0, e = SD.fixup_size(); i != e; ++i)
|
|
|
|
ComputeRelocationInfo(Asm, SD.getFixups()[e - i - 1], SymbolMap,
|
|
|
|
RelocInfos);
|
|
|
|
|
|
|
|
unsigned NumRelocs = RelocInfos.size() - NumRelocsStart;
|
|
|
|
uint64_t SectionStart = SectionDataStart + SD.getAddress();
|
|
|
|
WriteSection32(SD, SectionStart, RelocTableEnd, NumRelocs);
|
|
|
|
RelocTableEnd += NumRelocs * RelocationInfoSize;
|
|
|
|
}
|
|
|
|
|
2009-08-22 10:13:24 +00:00
|
|
|
// Write the symbol table load command, if used.
|
|
|
|
if (NumSymbols) {
|
|
|
|
unsigned FirstLocalSymbol = 0;
|
2009-08-22 11:41:10 +00:00
|
|
|
unsigned NumLocalSymbols = LocalSymbolData.size();
|
|
|
|
unsigned FirstExternalSymbol = FirstLocalSymbol + NumLocalSymbols;
|
|
|
|
unsigned NumExternalSymbols = ExternalSymbolData.size();
|
|
|
|
unsigned FirstUndefinedSymbol = FirstExternalSymbol + NumExternalSymbols;
|
|
|
|
unsigned NumUndefinedSymbols = UndefinedSymbolData.size();
|
2009-08-24 11:56:58 +00:00
|
|
|
unsigned NumIndirectSymbols = Asm.indirect_symbol_size();
|
|
|
|
unsigned NumSymTabSymbols =
|
|
|
|
NumLocalSymbols + NumExternalSymbols + NumUndefinedSymbols;
|
|
|
|
uint64_t IndirectSymbolSize = NumIndirectSymbols * 4;
|
|
|
|
uint64_t IndirectSymbolOffset = 0;
|
|
|
|
|
|
|
|
// If used, the indirect symbols are written after the section data.
|
|
|
|
if (NumIndirectSymbols)
|
2009-08-26 13:58:10 +00:00
|
|
|
IndirectSymbolOffset = RelocTableEnd;
|
2009-08-24 11:56:58 +00:00
|
|
|
|
|
|
|
// The symbol table is written after the indirect symbol data.
|
2009-08-26 13:58:10 +00:00
|
|
|
uint64_t SymbolTableOffset = RelocTableEnd + IndirectSymbolSize;
|
2009-08-24 11:56:58 +00:00
|
|
|
|
|
|
|
// The string table is written after symbol table.
|
|
|
|
uint64_t StringTableOffset =
|
|
|
|
SymbolTableOffset + NumSymTabSymbols * Nlist32Size;
|
|
|
|
WriteSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols,
|
|
|
|
StringTableOffset, StringTable.size());
|
|
|
|
|
2009-08-22 10:13:24 +00:00
|
|
|
WriteDysymtabLoadCommand(FirstLocalSymbol, NumLocalSymbols,
|
|
|
|
FirstExternalSymbol, NumExternalSymbols,
|
|
|
|
FirstUndefinedSymbol, NumUndefinedSymbols,
|
|
|
|
IndirectSymbolOffset, NumIndirectSymbols);
|
|
|
|
}
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
|
2009-08-22 10:13:24 +00:00
|
|
|
// Write the actual section data.
|
|
|
|
for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it)
|
|
|
|
WriteFileData(OS, *it, *this);
|
|
|
|
|
2009-08-26 13:58:10 +00:00
|
|
|
// Write the relocation entries.
|
|
|
|
for (unsigned i = 0, e = RelocInfos.size(); i != e; ++i) {
|
|
|
|
Write32(RelocInfos[i].Word0);
|
|
|
|
Write32(RelocInfos[i].Word1);
|
|
|
|
}
|
|
|
|
|
2009-08-22 10:13:24 +00:00
|
|
|
// Write the symbol table data, if used.
|
|
|
|
if (NumSymbols) {
|
2009-08-24 11:56:58 +00:00
|
|
|
// Write the indirect symbol entries.
|
2009-08-26 00:18:21 +00:00
|
|
|
for (MCAssembler::indirect_symbol_iterator
|
|
|
|
it = Asm.indirect_symbol_begin(),
|
|
|
|
ie = Asm.indirect_symbol_end(); it != ie; ++it) {
|
|
|
|
// Indirect symbols in the non lazy symbol pointer section have some
|
|
|
|
// special handling.
|
|
|
|
const MCSectionMachO &Section =
|
|
|
|
static_cast<const MCSectionMachO&>(it->SectionData->getSection());
|
|
|
|
unsigned Type =
|
|
|
|
Section.getTypeAndAttributes() & MCSectionMachO::SECTION_TYPE;
|
|
|
|
if (Type == MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) {
|
|
|
|
// If this symbol is defined and internal, mark it as such.
|
|
|
|
if (it->Symbol->isDefined() &&
|
|
|
|
!SymbolMap.lookup(it->Symbol)->isExternal()) {
|
|
|
|
uint32_t Flags = ISF_Local;
|
|
|
|
if (it->Symbol->isAbsolute())
|
|
|
|
Flags |= ISF_Absolute;
|
|
|
|
Write32(Flags);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-26 13:57:54 +00:00
|
|
|
Write32(SymbolMap[it->Symbol]->getIndex());
|
2009-08-26 00:18:21 +00:00
|
|
|
}
|
2009-08-22 10:13:24 +00:00
|
|
|
|
2009-08-24 11:56:58 +00:00
|
|
|
// FIXME: Check that offsets match computed ones.
|
2009-08-22 10:13:24 +00:00
|
|
|
|
|
|
|
// Write the symbol table entries.
|
2009-08-22 11:41:10 +00:00
|
|
|
for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i)
|
|
|
|
WriteNlist32(LocalSymbolData[i]);
|
|
|
|
for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i)
|
|
|
|
WriteNlist32(ExternalSymbolData[i]);
|
|
|
|
for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i)
|
|
|
|
WriteNlist32(UndefinedSymbolData[i]);
|
2009-08-22 10:13:24 +00:00
|
|
|
|
|
|
|
// Write the string table.
|
|
|
|
OS << StringTable.str();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
|
|
|
|
/* *** */
|
|
|
|
|
2009-08-21 18:29:01 +00:00
|
|
|
MCFragment::MCFragment() : Kind(FragmentType(~0)) {
|
|
|
|
}
|
|
|
|
|
2009-08-26 02:48:04 +00:00
|
|
|
MCFragment::MCFragment(FragmentType _Kind, MCSectionData *_Parent)
|
2009-08-21 18:29:01 +00:00
|
|
|
: Kind(_Kind),
|
2009-08-26 02:48:04 +00:00
|
|
|
Parent(_Parent),
|
2009-08-21 18:29:01 +00:00
|
|
|
FileSize(~UINT64_C(0))
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
{
|
2009-08-26 02:48:04 +00:00
|
|
|
if (Parent)
|
|
|
|
Parent->getFragmentList().push_back(this);
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-21 18:29:01 +00:00
|
|
|
MCFragment::~MCFragment() {
|
|
|
|
}
|
|
|
|
|
2009-08-26 02:48:04 +00:00
|
|
|
uint64_t MCFragment::getAddress() const {
|
|
|
|
assert(getParent() && "Missing Section!");
|
|
|
|
return getParent()->getAddress() + Offset;
|
|
|
|
}
|
|
|
|
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
/* *** */
|
|
|
|
|
|
|
|
MCSectionData::MCSectionData() : Section(*(MCSection*)0) {}
|
|
|
|
|
|
|
|
MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A)
|
|
|
|
: Section(_Section),
|
|
|
|
Alignment(1),
|
2009-08-26 02:48:04 +00:00
|
|
|
Address(~UINT64_C(0)),
|
2009-08-26 04:13:32 +00:00
|
|
|
Size(~UINT64_C(0)),
|
2009-08-26 13:58:10 +00:00
|
|
|
FileSize(~UINT64_C(0)),
|
|
|
|
LastFixupLookup(~0)
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
{
|
|
|
|
if (A)
|
|
|
|
A->getSectionList().push_back(this);
|
|
|
|
}
|
|
|
|
|
2009-08-26 13:58:10 +00:00
|
|
|
const MCSectionData::Fixup *
|
|
|
|
MCSectionData::LookupFixup(const MCFragment *Fragment, uint64_t Offset) const {
|
|
|
|
// Use a one level cache to turn the common case of accessing the fixups in
|
|
|
|
// order into O(1) instead of O(N).
|
|
|
|
unsigned i = LastFixupLookup, Count = Fixups.size(), End = Fixups.size();
|
|
|
|
if (i >= End)
|
|
|
|
i = 0;
|
|
|
|
while (Count--) {
|
|
|
|
const Fixup &F = Fixups[i];
|
|
|
|
if (F.Fragment == Fragment && F.Offset == Offset) {
|
|
|
|
LastFixupLookup = i;
|
|
|
|
return &F;
|
|
|
|
}
|
|
|
|
|
|
|
|
++i;
|
|
|
|
if (i == End)
|
|
|
|
i = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
/* *** */
|
|
|
|
|
2009-08-22 10:13:24 +00:00
|
|
|
MCSymbolData::MCSymbolData() : Symbol(*(MCSymbol*)0) {}
|
|
|
|
|
|
|
|
MCSymbolData::MCSymbolData(MCSymbol &_Symbol, MCFragment *_Fragment,
|
|
|
|
uint64_t _Offset, MCAssembler *A)
|
2009-08-22 11:41:10 +00:00
|
|
|
: Symbol(_Symbol), Fragment(_Fragment), Offset(_Offset),
|
2009-08-26 13:57:54 +00:00
|
|
|
IsExternal(false), IsPrivateExtern(false), Flags(0), Index(0)
|
2009-08-22 10:13:24 +00:00
|
|
|
{
|
|
|
|
if (A)
|
|
|
|
A->getSymbolList().push_back(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* *** */
|
|
|
|
|
2009-08-26 21:22:22 +00:00
|
|
|
MCAssembler::MCAssembler(raw_ostream &_OS)
|
|
|
|
: OS(_OS),
|
|
|
|
SubsectionsViaSymbols(false)
|
|
|
|
{
|
|
|
|
}
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
|
|
|
|
MCAssembler::~MCAssembler() {
|
|
|
|
}
|
|
|
|
|
2009-08-26 04:13:32 +00:00
|
|
|
void MCAssembler::LayoutSection(MCSectionData &SD, unsigned NextAlign) {
|
|
|
|
uint64_t Address = SD.getAddress();
|
2009-08-21 18:29:01 +00:00
|
|
|
|
|
|
|
for (MCSectionData::iterator it = SD.begin(), ie = SD.end(); it != ie; ++it) {
|
|
|
|
MCFragment &F = *it;
|
2009-08-21 23:07:38 +00:00
|
|
|
|
2009-08-26 04:13:32 +00:00
|
|
|
F.setOffset(Address - SD.getAddress());
|
2009-08-21 23:07:38 +00:00
|
|
|
|
|
|
|
// Evaluate fragment size.
|
|
|
|
switch (F.getKind()) {
|
|
|
|
case MCFragment::FT_Align: {
|
|
|
|
MCAlignFragment &AF = cast<MCAlignFragment>(F);
|
|
|
|
|
2009-08-26 04:13:32 +00:00
|
|
|
uint64_t Size = RoundUpToAlignment(Address, AF.getAlignment()) - Address;
|
|
|
|
if (Size > AF.getMaxBytesToEmit())
|
2009-08-21 23:07:38 +00:00
|
|
|
AF.setFileSize(0);
|
|
|
|
else
|
2009-08-26 04:13:32 +00:00
|
|
|
AF.setFileSize(Size);
|
2009-08-21 23:07:38 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MCFragment::FT_Data:
|
|
|
|
F.setFileSize(F.getMaxFileSize());
|
|
|
|
break;
|
|
|
|
|
2009-08-26 13:58:10 +00:00
|
|
|
case MCFragment::FT_Fill: {
|
|
|
|
MCFillFragment &FF = cast<MCFillFragment>(F);
|
|
|
|
|
|
|
|
F.setFileSize(F.getMaxFileSize());
|
|
|
|
|
|
|
|
// If the fill value is constant, thats it.
|
|
|
|
if (FF.getValue().isAbsolute())
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Otherwise, add fixups for the values.
|
|
|
|
for (uint64_t i = 0, e = FF.getCount(); i != e; ++i) {
|
|
|
|
MCSectionData::Fixup Fix(F, i * FF.getValueSize(),
|
|
|
|
FF.getValue(),FF.getValueSize());
|
|
|
|
SD.getFixups().push_back(Fix);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-08-21 23:07:38 +00:00
|
|
|
case MCFragment::FT_Org: {
|
|
|
|
MCOrgFragment &OF = cast<MCOrgFragment>(F);
|
|
|
|
|
|
|
|
if (!OF.getOffset().isAbsolute())
|
|
|
|
llvm_unreachable("FIXME: Not yet implemented!");
|
|
|
|
uint64_t OrgOffset = OF.getOffset().getConstant();
|
2009-08-26 04:13:32 +00:00
|
|
|
uint64_t Offset = Address - SD.getAddress();
|
2009-08-21 23:07:38 +00:00
|
|
|
|
|
|
|
// FIXME: We need a way to communicate this error.
|
2009-08-22 08:27:54 +00:00
|
|
|
if (OrgOffset < Offset)
|
2009-08-21 23:07:38 +00:00
|
|
|
llvm_report_error("invalid .org offset '" + Twine(OrgOffset) +
|
2009-08-26 04:13:32 +00:00
|
|
|
"' (at offset '" + Twine(Offset) + "'");
|
2009-08-21 23:07:38 +00:00
|
|
|
|
2009-08-22 08:27:54 +00:00
|
|
|
F.setFileSize(OrgOffset - Offset);
|
2009-08-21 23:07:38 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-26 04:13:32 +00:00
|
|
|
Address += F.getFileSize();
|
2009-08-21 18:29:01 +00:00
|
|
|
}
|
|
|
|
|
2009-08-26 04:13:32 +00:00
|
|
|
// Set the section sizes.
|
|
|
|
SD.setSize(Address - SD.getAddress());
|
|
|
|
SD.setFileSize(RoundUpToAlignment(Address, NextAlign) - SD.getAddress());
|
2009-08-21 18:29:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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;
|
|
|
|
|
2009-08-25 21:10:45 +00:00
|
|
|
++EmittedFragments;
|
|
|
|
|
2009-08-21 18:29:01 +00:00
|
|
|
// FIXME: Embed in fragments instead?
|
|
|
|
switch (F.getKind()) {
|
2009-08-21 23:07:38 +00:00
|
|
|
case MCFragment::FT_Align: {
|
|
|
|
MCAlignFragment &AF = cast<MCAlignFragment>(F);
|
|
|
|
uint64_t Count = AF.getFileSize() / AF.getValueSize();
|
|
|
|
|
|
|
|
// FIXME: This error shouldn't actually occur (the front end should emit
|
|
|
|
// multiple .align directives to enforce the semantics it wants), but is
|
|
|
|
// severe enough that we want to report it. How to handle this?
|
|
|
|
if (Count * AF.getValueSize() != AF.getFileSize())
|
|
|
|
llvm_report_error("undefined .align directive, value size '" +
|
|
|
|
Twine(AF.getValueSize()) +
|
|
|
|
"' is not a divisor of padding size '" +
|
|
|
|
Twine(AF.getFileSize()) + "'");
|
|
|
|
|
|
|
|
for (uint64_t i = 0; i != Count; ++i) {
|
|
|
|
switch (AF.getValueSize()) {
|
|
|
|
default:
|
|
|
|
assert(0 && "Invalid size!");
|
|
|
|
case 1: MOW.Write8 (uint8_t (AF.getValue())); break;
|
|
|
|
case 2: MOW.Write16(uint16_t(AF.getValue())); break;
|
|
|
|
case 4: MOW.Write32(uint32_t(AF.getValue())); break;
|
|
|
|
case 8: MOW.Write64(uint64_t(AF.getValue())); break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2009-08-21 18:29:01 +00:00
|
|
|
|
|
|
|
case MCFragment::FT_Data:
|
|
|
|
OS << cast<MCDataFragment>(F).getContents().str();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MCFragment::FT_Fill: {
|
|
|
|
MCFillFragment &FF = cast<MCFillFragment>(F);
|
|
|
|
|
2009-08-26 13:58:10 +00:00
|
|
|
int64_t Value = 0;
|
2009-08-21 18:29:01 +00:00
|
|
|
if (!FF.getValue().isAbsolute())
|
2009-08-26 13:58:10 +00:00
|
|
|
Value = FF.getValue().getConstant();
|
2009-08-21 18:29:01 +00:00
|
|
|
for (uint64_t i = 0, e = FF.getCount(); i != e; ++i) {
|
2009-08-26 13:58:10 +00:00
|
|
|
if (!FF.getValue().isAbsolute()) {
|
|
|
|
// Find the fixup.
|
|
|
|
//
|
|
|
|
// FIXME: Find a better way to write in the fixes.
|
|
|
|
const MCSectionData::Fixup *Fixup =
|
|
|
|
F.getParent()->LookupFixup(&F, i * FF.getValueSize());
|
|
|
|
assert(Fixup && "Missing fixup for fill value!");
|
|
|
|
Value = Fixup->FixedValue;
|
|
|
|
}
|
|
|
|
|
2009-08-21 18:29:01 +00:00
|
|
|
switch (FF.getValueSize()) {
|
|
|
|
default:
|
|
|
|
assert(0 && "Invalid size!");
|
2009-08-21 23:07:38 +00:00
|
|
|
case 1: MOW.Write8 (uint8_t (Value)); break;
|
|
|
|
case 2: MOW.Write16(uint16_t(Value)); break;
|
|
|
|
case 4: MOW.Write32(uint32_t(Value)); break;
|
|
|
|
case 8: MOW.Write64(uint64_t(Value)); break;
|
2009-08-21 18:29:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-08-21 23:07:38 +00:00
|
|
|
case MCFragment::FT_Org: {
|
|
|
|
MCOrgFragment &OF = cast<MCOrgFragment>(F);
|
|
|
|
|
|
|
|
for (uint64_t i = 0, e = OF.getFileSize(); i != e; ++i)
|
|
|
|
MOW.Write8(uint8_t(OF.getValue()));
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2009-08-21 18:29:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2009-08-26 04:13:32 +00:00
|
|
|
// Add section padding.
|
|
|
|
assert(SD.getFileSize() >= SD.getSize() && "Invalid section sizes!");
|
|
|
|
MOW.WriteZeros(SD.getFileSize() - SD.getSize());
|
|
|
|
|
2009-08-21 18:29:01 +00:00
|
|
|
assert(OS.tell() - Start == SD.getFileSize());
|
|
|
|
}
|
|
|
|
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
void MCAssembler::Finish() {
|
2009-08-21 18:29:01 +00:00
|
|
|
// Layout the sections and fragments.
|
2009-08-26 02:48:04 +00:00
|
|
|
uint64_t Address = 0;
|
2009-08-26 04:13:32 +00:00
|
|
|
for (iterator it = begin(), ie = end(); it != ie;) {
|
|
|
|
MCSectionData &SD = *it;
|
|
|
|
|
|
|
|
// Select the amount of padding alignment we need, based on either the next
|
|
|
|
// sections alignment or the default alignment.
|
|
|
|
//
|
|
|
|
// FIXME: This should probably match the native word size.
|
|
|
|
unsigned NextAlign = 4;
|
|
|
|
++it;
|
|
|
|
if (it != ie)
|
|
|
|
NextAlign = it->getAlignment();
|
|
|
|
|
|
|
|
// Layout the section fragments and its size.
|
|
|
|
SD.setAddress(Address);
|
|
|
|
LayoutSection(SD, NextAlign);
|
|
|
|
Address += SD.getFileSize();
|
2009-08-26 02:48:04 +00:00
|
|
|
}
|
2009-08-21 18:29:01 +00:00
|
|
|
|
2009-08-22 10:13:24 +00:00
|
|
|
// Write the object file.
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
MachObjectWriter MOW(OS);
|
2009-08-22 10:13:24 +00:00
|
|
|
MOW.WriteObject(*this);
|
2009-08-21 18:29:01 +00:00
|
|
|
|
llvm-mc: Start MCAssembler and MCMachOStreamer.
- Together these form the (Mach-O) back end of the assembler.
- MCAssembler is the actual assembler backend, which is designed to have a
reasonable API. This will eventually grow to support multiple object file
implementations, but for now its Mach-O/i386 only.
- MCMachOStreamer adapts the MCStreamer "actions" API to the MCAssembler API,
e.g. converting the various directives into fragments, managing state like
the current section, and so on.
- llvm-mc will use the new backend via '-filetype=obj', which may eventually
be, but is not yet, since I hear that people like assemblers which actually
assemble.
- The only thing that works at the moment is changing sections. For the time
being I have a Python Mach-O dumping tool in test/scripts so this stuff can
be easily tested, eventually I expect to replace this with a real LLVM tool.
- More doxyments to come.
I assume that since this stuff doesn't touch any of the things which are part of
2.6 that it is ok to put this in not so long before the freeze, but if someone
objects let me know, I can pull it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79612 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-21 09:11:24 +00:00
|
|
|
OS.flush();
|
|
|
|
}
|