summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/MC/MCAssembler.h12
-rw-r--r--include/llvm/MC/MCMachObjectWriter.h2
-rw-r--r--include/llvm/Object/MachOFormat.h11
-rw-r--r--include/llvm/Object/MachOObject.h3
-rw-r--r--lib/MC/MCMachOStreamer.cpp5
-rw-r--r--lib/MC/MachObjectWriter.cpp56
-rw-r--r--lib/Object/MachOObject.cpp11
-rw-r--r--test/MC/MachO/linker-option-2.s25
-rw-r--r--tools/macho-dump/macho-dump.cpp30
9 files changed, 148 insertions, 7 deletions
diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h
index 981002f798..2edd956108 100644
--- a/include/llvm/MC/MCAssembler.h
+++ b/include/llvm/MC/MCAssembler.h
@@ -849,6 +849,10 @@ private:
std::vector<IndirectSymbolData> IndirectSymbols;
std::vector<DataRegionData> DataRegions;
+
+ /// The list of linker options to propagate into the object file.
+ std::vector<std::vector<std::string> > LinkerOptions;
+
/// The set of function symbols for which a .thumb_func directive has
/// been seen.
//
@@ -1060,6 +1064,14 @@ public:
size_t indirect_symbol_size() const { return IndirectSymbols.size(); }
/// @}
+ /// @name Linker Option List Access
+ /// @{
+
+ std::vector<std::vector<std::string> > &getLinkerOptions() {
+ return LinkerOptions;
+ }
+
+ /// @}
/// @name Data Region List Access
/// @{
diff --git a/include/llvm/MC/MCMachObjectWriter.h b/include/llvm/MC/MCMachObjectWriter.h
index 3cd278e7c0..3c9a588d04 100644
--- a/include/llvm/MC/MCMachObjectWriter.h
+++ b/include/llvm/MC/MCMachObjectWriter.h
@@ -196,6 +196,8 @@ public:
void WriteLinkeditLoadCommand(uint32_t Type, uint32_t DataOffset,
uint32_t DataSize);
+ void WriteLinkerOptionsLoadCommand(const std::vector<std::string> &Options);
+
// FIXME: We really need to improve the relocation validation. Basically, we
// want to implement a separate computation which evaluates the relocation
// entry as the linker would, and verifies that the resultant fixup value is
diff --git a/include/llvm/Object/MachOFormat.h b/include/llvm/Object/MachOFormat.h
index 001cb6540a..ffca391ea2 100644
--- a/include/llvm/Object/MachOFormat.h
+++ b/include/llvm/Object/MachOFormat.h
@@ -148,7 +148,8 @@ namespace macho {
LCT_CodeSignature = 0x1d,
LCT_SegmentSplitInfo = 0x1e,
LCT_FunctionStarts = 0x26,
- LCT_DataInCode = 0x29
+ LCT_DataInCode = 0x29,
+ LCT_LinkerOptions = 0x2D
};
/// \brief Load command structure.
@@ -236,6 +237,14 @@ namespace macho {
uint32_t DataSize;
};
+ struct LinkerOptionsLoadCommand {
+ uint32_t Type;
+ uint32_t Size;
+ uint32_t Count;
+ // Load command is followed by Count number of zero-terminated UTF8 strings,
+ // and then zero-filled to be 4-byte aligned.
+ };
+
/// @}
/// @name Section Data
/// @{
diff --git a/include/llvm/Object/MachOObject.h b/include/llvm/Object/MachOObject.h
index e32a85d140..9e4ab199f5 100644
--- a/include/llvm/Object/MachOObject.h
+++ b/include/llvm/Object/MachOObject.h
@@ -153,6 +153,9 @@ public:
void ReadLinkeditDataLoadCommand(
const LoadCommandInfo &LCI,
InMemoryStruct<macho::LinkeditDataLoadCommand> &Res) const;
+ void ReadLinkerOptionsLoadCommand(
+ const LoadCommandInfo &LCI,
+ InMemoryStruct<macho::LinkerOptionsLoadCommand> &Res) const;
void ReadIndirectSymbolTableEntry(
const macho::DysymtabLoadCommand &DLC,
unsigned Index,
diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp
index f947dda83d..2c0c97af47 100644
--- a/lib/MC/MCMachOStreamer.cpp
+++ b/lib/MC/MCMachOStreamer.cpp
@@ -48,6 +48,7 @@ public:
virtual void EmitEHSymAttributes(const MCSymbol *Symbol,
MCSymbol *EHSymbol);
virtual void EmitAssemblerFlag(MCAssemblerFlag Flag);
+ virtual void EmitLinkerOptions(ArrayRef<std::string> Options);
virtual void EmitDataRegion(MCDataRegionType Kind);
virtual void EmitThumbFunc(MCSymbol *Func);
virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute);
@@ -178,6 +179,10 @@ void MCMachOStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
}
}
+void MCMachOStreamer::EmitLinkerOptions(ArrayRef<std::string> Options) {
+ getAssembler().getLinkerOptions().push_back(Options);
+}
+
void MCMachOStreamer::EmitDataRegion(MCDataRegionType Kind) {
switch (Kind) {
case MCDR_DataRegion:
diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp
index 0098bead45..d13c178a9c 100644
--- a/lib/MC/MachObjectWriter.cpp
+++ b/lib/MC/MachObjectWriter.cpp
@@ -376,6 +376,39 @@ void MachObjectWriter::WriteLinkeditLoadCommand(uint32_t Type,
assert(OS.tell() - Start == macho::LinkeditLoadCommandSize);
}
+static unsigned ComputeLinkerOptionsLoadCommandSize(
+ const std::vector<std::string> &Options)
+{
+ unsigned Size = sizeof(macho::LinkerOptionsLoadCommand);
+ for (unsigned i = 0, e = Options.size(); i != e; ++i)
+ Size += Options[i].size() + 1;
+ return RoundUpToAlignment(Size, 4);
+}
+
+void MachObjectWriter::WriteLinkerOptionsLoadCommand(
+ const std::vector<std::string> &Options)
+{
+ unsigned Size = ComputeLinkerOptionsLoadCommandSize(Options);
+ uint64_t Start = OS.tell();
+ (void) Start;
+
+ Write32(macho::LCT_LinkerOptions);
+ Write32(Size);
+ Write32(Options.size());
+ uint64_t BytesWritten = 0;
+ for (unsigned i = 0, e = Options.size(); i != e; ++i) {
+ // Write each string, including the null byte.
+ const std::string &Option = Options[i];
+ WriteBytes(Option.c_str(), Option.size() + 1);
+ BytesWritten += Option.size() + 1;
+ }
+
+ // Pad to a multiple of 4.
+ WriteBytes("", OffsetToAlignment(BytesWritten, 4));
+
+ assert(OS.tell() - Start == Size);
+}
+
void MachObjectWriter::RecordRelocation(const MCAssembler &Asm,
const MCAsmLayout &Layout,
@@ -693,6 +726,13 @@ void MachObjectWriter::WriteObject(MCAssembler &Asm,
macho::SegmentLoadCommand64Size + NumSections * macho::Section64Size :
macho::SegmentLoadCommand32Size + NumSections * macho::Section32Size;
+ // Add the data-in-code load command size, if used.
+ unsigned NumDataRegions = Asm.getDataRegions().size();
+ if (NumDataRegions) {
+ ++NumLoadCommands;
+ LoadCommandsSize += macho::LinkeditLoadCommandSize;
+ }
+
// Add the symbol table load command sizes, if used.
unsigned NumSymbols = LocalSymbolData.size() + ExternalSymbolData.size() +
UndefinedSymbolData.size();
@@ -702,13 +742,14 @@ void MachObjectWriter::WriteObject(MCAssembler &Asm,
macho::DysymtabLoadCommandSize);
}
- // Add the data-in-code load command size, if used.
- unsigned NumDataRegions = Asm.getDataRegions().size();
- if (NumDataRegions) {
+ // Add the linker option load commands sizes.
+ const std::vector<std::vector<std::string> > &LinkerOptions =
+ Asm.getLinkerOptions();
+ for (unsigned i = 0, e = LinkerOptions.size(); i != e; ++i) {
++NumLoadCommands;
- LoadCommandsSize += macho::LinkeditLoadCommandSize;
+ LoadCommandsSize += ComputeLinkerOptionsLoadCommandSize(LinkerOptions[i]);
}
-
+
// Compute the total size of the section data, as well as its file size and vm
// size.
uint64_t SectionDataStart = (is64Bit() ? macho::Header64Size :
@@ -799,6 +840,11 @@ void MachObjectWriter::WriteObject(MCAssembler &Asm,
IndirectSymbolOffset, NumIndirectSymbols);
}
+ // Write the linker options load commands.
+ for (unsigned i = 0, e = LinkerOptions.size(); i != e; ++i) {
+ WriteLinkerOptionsLoadCommand(LinkerOptions[i]);
+ }
+
// Write the actual section data.
for (MCAssembler::const_iterator it = Asm.begin(),
ie = Asm.end(); it != ie; ++it) {
diff --git a/lib/Object/MachOObject.cpp b/lib/Object/MachOObject.cpp
index 529bdf97e5..c9c341a207 100644
--- a/lib/Object/MachOObject.cpp
+++ b/lib/Object/MachOObject.cpp
@@ -259,6 +259,17 @@ void MachOObject::ReadLinkeditDataLoadCommand(const LoadCommandInfo &LCI,
}
template<>
+void SwapStruct(macho::LinkerOptionsLoadCommand &Value) {
+ SwapValue(Value.Type);
+ SwapValue(Value.Size);
+ SwapValue(Value.Count);
+}
+void MachOObject::ReadLinkerOptionsLoadCommand(const LoadCommandInfo &LCI,
+ InMemoryStruct<macho::LinkerOptionsLoadCommand> &Res) const {
+ ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res);
+}
+
+template<>
void SwapStruct(macho::IndirectSymbolTableEntry &Value) {
SwapValue(Value.Index);
}
diff --git a/test/MC/MachO/linker-option-2.s b/test/MC/MachO/linker-option-2.s
new file mode 100644
index 0000000000..bb5966be27
--- /dev/null
+++ b/test/MC/MachO/linker-option-2.s
@@ -0,0 +1,25 @@
+// RUN: llvm-mc -n -triple x86_64-apple-darwin10 %s -filetype=obj | macho-dump | FileCheck %s
+
+// CHECK: ('load_commands_size', 104)
+// CHECK: ('load_commands', [
+// CHECK: # Load Command 1
+// CHECK: (('command', 45)
+// CHECK: ('size', 16)
+// CHECK: ('count', 1)
+// CHECK: ('_strings', [
+// CHECK: "a",
+// CHECK: ])
+// CHECK: ),
+// CHECK: # Load Command 2
+// CHECK: (('command', 45)
+// CHECK: ('size', 16)
+// CHECK: ('count', 2)
+// CHECK: ('_strings', [
+// CHECK: "a",
+// CHECK: "b",
+// CHECK: ])
+// CHECK: ),
+// CHECK: ])
+
+.linker_option "a"
+.linker_option "a", "b"
diff --git a/tools/macho-dump/macho-dump.cpp b/tools/macho-dump/macho-dump.cpp
index 20deda9a0c..3bd3ecc8fd 100644
--- a/tools/macho-dump/macho-dump.cpp
+++ b/tools/macho-dump/macho-dump.cpp
@@ -337,7 +337,7 @@ static int DumpDataInCodeDataCommand(MachOObject &Obj,
InMemoryStruct<macho::LinkeditDataLoadCommand> LLC;
Obj.ReadLinkeditDataLoadCommand(LCI, LLC);
if (!LLC)
- return Error("unable to read segment load command");
+ return Error("unable to read data-in-code load command");
outs() << " ('dataoff', " << LLC->DataOffset << ")\n"
<< " ('datasize', " << LLC->DataSize << ")\n"
@@ -361,6 +361,31 @@ static int DumpDataInCodeDataCommand(MachOObject &Obj,
return 0;
}
+static int DumpLinkerOptionsCommand(MachOObject &Obj,
+ const MachOObject::LoadCommandInfo &LCI) {
+ InMemoryStruct<macho::LinkerOptionsLoadCommand> LOLC;
+ Obj.ReadLinkerOptionsLoadCommand(LCI, LOLC);
+ if (!LOLC)
+ return Error("unable to read linker options load command");
+
+ outs() << " ('count', " << LOLC->Count << ")\n"
+ << " ('_strings', [\n";
+
+ uint64_t DataSize = LOLC->Size - sizeof(macho::LinkerOptionsLoadCommand);
+ StringRef Data = Obj.getData(
+ LCI.Offset + sizeof(macho::LinkerOptionsLoadCommand), DataSize);
+ for (unsigned i = 0; i != LOLC->Count; ++i) {
+ std::pair<StringRef,StringRef> Split = Data.split('\0');
+ outs() << "\t\"";
+ outs().write_escaped(Split.first);
+ outs() << "\",\n";
+ Data = Split.second;
+ }
+ outs() <<" ])\n";
+
+ return 0;
+}
+
static int DumpLoadCommand(MachOObject &Obj, unsigned Index) {
const MachOObject::LoadCommandInfo &LCI = Obj.getLoadCommandInfo(Index);
@@ -390,6 +415,9 @@ static int DumpLoadCommand(MachOObject &Obj, unsigned Index) {
case macho::LCT_DataInCode:
Res = DumpDataInCodeDataCommand(Obj, LCI);
break;
+ case macho::LCT_LinkerOptions:
+ Res = DumpLinkerOptionsCommand(Obj, LCI);
+ break;
default:
Warning("unknown load command: " + Twine(LCI.Command.Type));
break;