[MC/Mach-O] Add support for linker options in Mach-O files.

llvm-svn: 172779
This commit is contained in:
Daniel Dunbar 2013-01-18 01:26:07 +00:00
parent 16004b8324
commit eec0f32eea
9 changed files with 148 additions and 7 deletions

View File

@ -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.
//
@ -1059,6 +1063,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
/// @{

View File

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

View File

@ -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
/// @{

View File

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

View File

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

View File

@ -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,11 +742,12 @@ 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
@ -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) {

View File

@ -258,6 +258,17 @@ void MachOObject::ReadLinkeditDataLoadCommand(const LoadCommandInfo &LCI,
ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res);
}
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);

View File

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

View File

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