diff --git a/llvm/test/tools/llvm-objcopy/MachO/Inputs/only-section.yaml b/llvm/test/tools/llvm-objcopy/MachO/Inputs/only-section.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/Inputs/only-section.yaml @@ -0,0 +1,115 @@ + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 4 + sizeofcmds: 440 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 312 + segname: '' + vmaddr: 0 + vmsize: 128 + fileoff: 472 + filesize: 128 + maxprot: 7 + initprot: 7 + nsects: 3 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000000000000 + size: 26 + offset: 0x000001D8 + align: 4 + reloff: 0x00000258 + nreloc: 2 + flags: 0x80000400 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __compact_unwind + segname: __LD + addr: 0x0000000000000020 + size: 32 + offset: 0x000001F8 + align: 3 + reloff: 0x00000268 + nreloc: 1 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __eh_frame + segname: __TEXT + addr: 0x0000000000000040 + size: 64 + offset: 0x00000218 + align: 3 + reloff: 0x00000000 + nreloc: 0 + flags: 0x6800000B + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - cmd: LC_BUILD_VERSION + cmdsize: 24 + platform: 1 + minos: 658944 + sdk: 0 + ntools: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 624 + nsyms: 3 + stroff: 672 + strsize: 12 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 0 + iextdefsym: 0 + nextdefsym: 1 + iundefsym: 1 + nundefsym: 2 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 +LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + - n_strx: 9 + n_type: 0x01 + n_sect: 0 + n_desc: 512 + n_value: 4 + - n_strx: 6 + n_type: 0x01 + n_sect: 0 + n_desc: 512 + n_value: 4 + StringTable: + - '' + - _foo + - _b + - _a +... diff --git a/llvm/test/tools/llvm-objcopy/MachO/only-section.test b/llvm/test/tools/llvm-objcopy/MachO/only-section.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/only-section.test @@ -0,0 +1,24 @@ +RUN: yaml2obj %p/Inputs/only-section.yaml > %t + +RUN: not llvm-objcopy --only-section __text %t %t2 2>&1 \ +RUN: | FileCheck %s -DINPUT=%t --check-prefix=BAD-SECTION-NAME +BAD-SECTION-NAME: error: '[[INPUT]]': Invalid section name (should be formatted as ",
") + +RUN: llvm-objcopy --only-section __TEXT,__text %t %t3 +RUN: llvm-readobj --sections %t3 | FileCheck %s --check-prefix=ONLY-TEXT-SECTION +ONLY-TEXT-SECTION: Name: __text +ONLY-TEXT-SECTION-NOT: Name: __compact_unwind +ONLY-TEXT-SECTION-NOT: Name: __eh_frame + +# Specify all sections. The output file should be the same as the input. +RUN: llvm-objcopy --only-section __TEXT,__text --only-section __TEXT,__eh_frame \ +RUN: --only-section __LD,__compact_unwind %t %t4 +RUN: cmp %t %t4 + +# Remove all sections without warning if the specified section name is not +# present in the input. +RUN: llvm-objcopy --only-section __TEXT,__foo %t %t5 +RUN: llvm-readobj --sections %t5 | FileCheck %s --check-prefix=NONEXISTENT-SECTION +NONEXISTENT-SECTION-NOT: Name: __text +NONEXISTENT-SECTION-NOT: Name: __compact_unwind +NONEXISTENT-SECTION-NOT: Name: __eh_frame diff --git a/llvm/tools/llvm-objcopy/CopyConfig.h b/llvm/tools/llvm-objcopy/CopyConfig.h --- a/llvm/tools/llvm-objcopy/CopyConfig.h +++ b/llvm/tools/llvm-objcopy/CopyConfig.h @@ -96,6 +96,11 @@ NameOrRegex(StringRef Pattern, bool IsRegex); bool operator==(StringRef S) const { return R ? R->match(S) : Name == S; } bool operator!=(StringRef S) const { return !operator==(S); } + + // Checks if this is a cannonical name (",
"). + bool isMachOCannonicalName() const { + return R ? true : Name.contains(','); + } }; struct NewSymbolInfo { diff --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp --- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp @@ -18,6 +18,34 @@ namespace macho { using namespace object; +using SectionPred = std::function; + +static void removeSections(const CopyConfig &Config, Object &Obj) { + SectionPred RemovePred = [](const Section &) { return false; }; + + if (!Config.OnlySection.empty()) { + RemovePred = [&Config, RemovePred](const Section &Sec) { + return !is_contained(Config.OnlySection, Sec.CannonicalName); + }; + } + + return Obj.removeSections(RemovePred); +} + +static Error validateOptions(const CopyConfig &Config) { + // TODO: Support section renaming in GNU objcopy for compatibility (see + // http://lists.llvm.org/pipermail/llvm-dev/2019-May/132570.html). + + if (!Config.OnlySection.empty()) { + for (const NameOrRegex &NR : Config.OnlySection) + if (!NR.isMachOCannonicalName()) + return createStringError(errc::invalid_argument, + "Invalid section name (should be formatted as " + "\",
\")"); + } + + return Error::success(); +} static Error handleArgs(const CopyConfig &Config, Object &Obj) { if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() || @@ -25,10 +53,10 @@ !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() || !Config.AllocSectionsPrefix.empty() || !Config.AddSection.empty() || !Config.DumpSection.empty() || !Config.KeepSection.empty() || - !Config.OnlySection.empty() || !Config.SymbolsToGlobalize.empty() || - !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() || - !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() || - !Config.SectionsToRename.empty() || !Config.SymbolsToRename.empty() || + !Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() || + !Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() || + !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() || + !Config.SymbolsToRename.empty() || !Config.UnneededSymbolsToRemove.empty() || !Config.SetSectionFlags.empty() || !Config.ToRemove.empty() || Config.ExtractDWO || Config.KeepFileSymbols || Config.LocalizeHidden || @@ -41,6 +69,10 @@ "option not supported by llvm-objcopy for MachO"); } + if (auto E = validateOptions(Config)) + return E; + + removeSections(Config, Obj); return Error::success(); } diff --git a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp --- a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp @@ -35,6 +35,7 @@ .str(); S.Segname = StringRef(Sec.segname, strnlen(Sec.segname, sizeof(Sec.sectname))).str(); + S.CannonicalName = (Twine(S.Segname) + "," + S.Sectname).str(); S.Addr = Sec.addr; S.Size = Sec.size; S.Offset = Sec.offset; diff --git a/llvm/tools/llvm-objcopy/MachO/Object.h b/llvm/tools/llvm-objcopy/MachO/Object.h --- a/llvm/tools/llvm-objcopy/MachO/Object.h +++ b/llvm/tools/llvm-objcopy/MachO/Object.h @@ -38,6 +38,8 @@ struct Section { std::string Sectname; std::string Segname; + // CannonicalName is a string formatted as “,". + std::string CannonicalName; uint64_t Addr; uint64_t Size; uint32_t Offset; @@ -250,6 +252,8 @@ Optional DataInCodeCommandIndex; /// The index LC_FUNCTION_STARTS load comamnd if present. Optional FunctionStartsCommandIndex; + + void removeSections(function_ref ToRemove); }; } // end namespace macho diff --git a/llvm/tools/llvm-objcopy/MachO/Object.cpp b/llvm/tools/llvm-objcopy/MachO/Object.cpp --- a/llvm/tools/llvm-objcopy/MachO/Object.cpp +++ b/llvm/tools/llvm-objcopy/MachO/Object.cpp @@ -10,6 +10,13 @@ return Symbols[Index].get(); } +void Object::removeSections(function_ref ToRemove) { + for (LoadCommand &LC : LoadCommands) + LC.Sections.erase(std::remove_if(std::begin(LC.Sections), + std::end(LC.Sections), ToRemove), + std::end(LC.Sections)); +} + } // end namespace macho } // end namespace objcopy } // end namespace llvm