forked from OSchip/llvm-project
[MC/Mach-O] Add support for linker options in Mach-O files.
llvm-svn: 172779
This commit is contained in:
parent
16004b8324
commit
eec0f32eea
|
@ -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
|
||||
/// @{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
/// @{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue