diff options
author | Chris Bieneman <beanz@apple.com> | 2016-06-24 20:42:28 +0000 |
---|---|---|
committer | Chris Bieneman <beanz@apple.com> | 2016-06-24 20:42:28 +0000 |
commit | 93e711938050e35f5275a1b36fae25226c25fc63 (patch) | |
tree | 92e6e7e0739f0c986b8d7c821aa0b374ce1a0f0c /llvm/tools | |
parent | 2e6d2d48205f272c39a50ae93ae4c700888e11e3 (diff) | |
download | bcm5719-llvm-93e711938050e35f5275a1b36fae25226c25fc63.tar.gz bcm5719-llvm-93e711938050e35f5275a1b36fae25226c25fc63.zip |
[obj2yaml] [yaml2obj] Support for MachO Universal binaries
This patch adds round-trip support for MachO Universal binaries to obj2yaml and yaml2obj. Universal binaries have a header and list of architecture structures, followed by a the individual object files at specified offsets.
llvm-svn: 273719
Diffstat (limited to 'llvm/tools')
-rw-r--r-- | llvm/tools/obj2yaml/macho2yaml.cpp | 39 | ||||
-rw-r--r-- | llvm/tools/obj2yaml/obj2yaml.cpp | 6 | ||||
-rw-r--r-- | llvm/tools/obj2yaml/obj2yaml.h | 2 | ||||
-rw-r--r-- | llvm/tools/yaml2obj/yaml2macho.cpp | 107 |
4 files changed, 144 insertions, 10 deletions
diff --git a/llvm/tools/obj2yaml/macho2yaml.cpp b/llvm/tools/obj2yaml/macho2yaml.cpp index 24bd6a60da4..060a2b82726 100644 --- a/llvm/tools/obj2yaml/macho2yaml.cpp +++ b/llvm/tools/obj2yaml/macho2yaml.cpp @@ -473,23 +473,52 @@ Error macho2yaml(raw_ostream &Out, const object::MachOObjectFile &Obj) { } Error macho2yaml(raw_ostream &Out, const object::MachOUniversalBinary &Obj) { - return make_error<Obj2YamlError>(obj2yaml_error::not_implemented); + MachOYAML::MachFile YAMLFile; + YAMLFile.isFat = true; + MachOYAML::UniversalBinary &YAML = YAMLFile.FatFile; + YAML.Header.magic = Obj.getMagic(); + YAML.Header.nfat_arch = Obj.getNumberOfObjects(); + + for (auto Slice : Obj.objects()) { + MachOYAML::FatArch arch; + arch.cputype = Slice.getCPUType(); + arch.cpusubtype = Slice.getCPUSubType(); + arch.offset = Slice.getOffset(); + arch.size = Slice.getSize(); + arch.align = Slice.getAlign(); + arch.reserved = Slice.getReserved(); + YAML.FatArchs.push_back(arch); + + auto SliceObj = Slice.getAsObjectFile(); + if (!SliceObj) + return SliceObj.takeError(); + + MachODumper Dumper(*SliceObj.get()); + Expected<std::unique_ptr<MachOYAML::Object>> YAMLObj = Dumper.dump(); + if (!YAMLObj) + return YAMLObj.takeError(); + YAML.Slices.push_back(*YAMLObj.get()); + } + + yaml::Output Yout(Out); + Yout << YAML; + return Error::success(); } -std::error_code macho2yaml(raw_ostream &Out, const object::ObjectFile &Obj) { - if (const auto *MachOObj = dyn_cast<object::MachOUniversalBinary>(&Obj)) { +std::error_code macho2yaml(raw_ostream &Out, const object::Binary &Binary) { + if (const auto *MachOObj = dyn_cast<object::MachOUniversalBinary>(&Binary)) { if (auto Err = macho2yaml(Out, *MachOObj)) { return errorToErrorCode(std::move(Err)); } return obj2yaml_error::success; } - if (const auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj)) { + if (const auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Binary)) { if (auto Err = macho2yaml(Out, *MachOObj)) { return errorToErrorCode(std::move(Err)); } return obj2yaml_error::success; } - + return obj2yaml_error::unsupported_obj_file_format; } diff --git a/llvm/tools/obj2yaml/obj2yaml.cpp b/llvm/tools/obj2yaml/obj2yaml.cpp index e243f2d843a..3f9373ee17e 100644 --- a/llvm/tools/obj2yaml/obj2yaml.cpp +++ b/llvm/tools/obj2yaml/obj2yaml.cpp @@ -24,8 +24,6 @@ static std::error_code dumpObject(const ObjectFile &Obj) { return coff2yaml(outs(), cast<COFFObjectFile>(Obj)); if (Obj.isELF()) return elf2yaml(outs(), Obj); - if (Obj.isMachO() || Obj.isMachOUniversalBinary()) - return macho2yaml(outs(), Obj); return obj2yaml_error::unsupported_obj_file_format; } @@ -36,6 +34,10 @@ static std::error_code dumpInput(StringRef File) { return errorToErrorCode(BinaryOrErr.takeError()); Binary &Binary = *BinaryOrErr.get().getBinary(); + // Universal MachO is not a subclass of ObjectFile, so it needs to be handled + // here with the other binary types. + if (Binary.isMachO() || Binary.isMachOUniversalBinary()) + return macho2yaml(outs(), Binary); // TODO: If this is an archive, then burst it and dump each entry if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary)) return dumpObject(*Obj); diff --git a/llvm/tools/obj2yaml/obj2yaml.h b/llvm/tools/obj2yaml/obj2yaml.h index c17b7d1642c..28c74751c0d 100644 --- a/llvm/tools/obj2yaml/obj2yaml.h +++ b/llvm/tools/obj2yaml/obj2yaml.h @@ -22,6 +22,6 @@ std::error_code coff2yaml(llvm::raw_ostream &Out, std::error_code elf2yaml(llvm::raw_ostream &Out, const llvm::object::ObjectFile &Obj); std::error_code macho2yaml(llvm::raw_ostream &Out, - const llvm::object::ObjectFile &Obj); + const llvm::object::Binary &Obj); #endif diff --git a/llvm/tools/yaml2obj/yaml2macho.cpp b/llvm/tools/yaml2obj/yaml2macho.cpp index 7821e63cf88..3d8be965209 100644 --- a/llvm/tools/yaml2obj/yaml2macho.cpp +++ b/llvm/tools/yaml2obj/yaml2macho.cpp @@ -424,17 +424,120 @@ Error MachOWriter::writeStringTable(raw_ostream &OS) { return Error::success(); } +class UniversalWriter { +public: + UniversalWriter(MachOYAML::MachFile &MachFile) + : MachFile(MachFile), fileStart(0) {} + + Error writeMachO(raw_ostream &OS); + +private: + Error writeFatHeader(raw_ostream &OS); + Error writeFatArchs(raw_ostream &OS); + + void ZeroToOffset(raw_ostream &OS, size_t offset); + + MachOYAML::MachFile &MachFile; + uint64_t fileStart; +}; + +Error UniversalWriter::writeMachO(raw_ostream &OS) { + fileStart = OS.tell(); + if (!MachFile.isFat) { + MachOWriter Writer(MachFile.ThinFile); + return Writer.writeMachO(OS); + } + if (auto Err = writeFatHeader(OS)) + return Err; + if (auto Err = writeFatArchs(OS)) + return Err; + auto &FatFile = MachFile.FatFile; + assert(FatFile.FatArchs.size() == FatFile.Slices.size()); + for (size_t i = 0; i < FatFile.Slices.size(); i++) { + ZeroToOffset(OS, FatFile.FatArchs[i].offset); + MachOWriter Writer(FatFile.Slices[i]); + if (auto Err = Writer.writeMachO(OS)) + return Err; + auto SliceEnd = FatFile.FatArchs[i].offset + FatFile.FatArchs[i].size; + ZeroToOffset(OS, SliceEnd); + } + return Error::success(); +} + +Error UniversalWriter::writeFatHeader(raw_ostream &OS) { + auto &FatFile = MachFile.FatFile; + MachO::fat_header header; + header.magic = FatFile.Header.magic; + header.nfat_arch = FatFile.Header.nfat_arch; + if (sys::IsLittleEndianHost) + swapStruct(header); + OS.write(reinterpret_cast<const char *>(&header), sizeof(MachO::fat_header)); + return Error::success(); +} + +template <typename FatArchType> +FatArchType constructFatArch(MachOYAML::FatArch &Arch) { + FatArchType FatArch; + FatArch.cputype = Arch.cputype; + FatArch.cpusubtype = Arch.cpusubtype; + FatArch.offset = Arch.offset; + FatArch.size = Arch.size; + FatArch.align = Arch.align; + return FatArch; +} + +template <typename StructType> +void writeFatArch(MachOYAML::FatArch &LC, raw_ostream &OS) {} + +template <> +void writeFatArch<MachO::fat_arch>(MachOYAML::FatArch &Arch, raw_ostream &OS) { + auto FatArch = constructFatArch<MachO::fat_arch>(Arch); + if (sys::IsLittleEndianHost) + swapStruct(FatArch); + OS.write(reinterpret_cast<const char *>(&FatArch), sizeof(MachO::fat_arch)); +} + +template <> +void writeFatArch<MachO::fat_arch_64>(MachOYAML::FatArch &Arch, + raw_ostream &OS) { + auto FatArch = constructFatArch<MachO::fat_arch_64>(Arch); + FatArch.reserved = Arch.reserved; + if (sys::IsLittleEndianHost) + swapStruct(FatArch); + OS.write(reinterpret_cast<const char *>(&FatArch), + sizeof(MachO::fat_arch_64)); +} + +Error UniversalWriter::writeFatArchs(raw_ostream &OS) { + auto &FatFile = MachFile.FatFile; + bool is64Bit = FatFile.Header.magic == MachO::FAT_MAGIC_64; + for (auto Arch : FatFile.FatArchs) { + if (is64Bit) + writeFatArch<MachO::fat_arch_64>(Arch, OS); + else + writeFatArch<MachO::fat_arch>(Arch, OS); + } + + return Error::success(); +} + +void UniversalWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) { + auto currOffset = OS.tell() - fileStart; + if (currOffset < Offset) + ZeroFillBytes(OS, Offset - currOffset); +} + } // end anonymous namespace int yaml2macho(yaml::Input &YIn, raw_ostream &Out) { - MachOYAML::Object Doc; + MachOYAML::MachFile Doc; YIn >> Doc; if (YIn.error()) { errs() << "yaml2obj: Failed to parse YAML file!\n"; return 1; } - MachOWriter Writer(Doc); + UniversalWriter Writer(Doc); if (auto Err = Writer.writeMachO(Out)) { errs() << toString(std::move(Err)); return 1; |