Skip to content

Commit

Permalink
[llvm-objcopy] [COFF] Add support for removing sections
Browse files Browse the repository at this point in the history
Differential Revision: https://reviews.llvm.org/D56683

llvm-svn: 351660
  • Loading branch information
mstorsjo committed Jan 19, 2019
1 parent e9f62f6 commit f9e1434
Show file tree
Hide file tree
Showing 7 changed files with 391 additions and 19 deletions.
210 changes: 210 additions & 0 deletions llvm/test/tools/llvm-objcopy/COFF/remove-section.test
@@ -0,0 +1,210 @@
# RUN: yaml2obj %s > %t.in.o
#
# RUN: llvm-objdump -section-headers %t.in.o | FileCheck %s --check-prefixes=SECTIONS-PRE
# RUN: llvm-objdump -t %t.in.o | FileCheck %s --check-prefixes=SYMBOLS-PRE
#
# RUN: llvm-objcopy -R .bss %t.in.o %t.remove-bss.o
# RUN: llvm-objdump -section-headers %t.remove-bss.o | FileCheck %s --check-prefix=SECTIONS-REMOVE-BSS
# RUN: llvm-objdump -t %t.remove-bss.o | FileCheck %s --check-prefix=SYMBOLS-REMOVE-BSS
#
# RUN: llvm-objcopy --remove-section .bss %t.in.o %t.cmp.o
# RUN: cmp %t.remove-bss.o %t.cmp.o
#
# RUN: llvm-objcopy -R .text %t.in.o %t.remove-text.o
# RUN: llvm-objdump -section-headers %t.remove-text.o | FileCheck %s --check-prefix=SECTIONS-REMOVE-TEXT
# RUN: llvm-objdump -t %t.remove-text.o | FileCheck %s --check-prefix=SYMBOLS-REMOVE-TEXT
#
# RUN: not llvm-objcopy -R .comdat %t.in.o %t.remove-comdat.o 2>&1 | FileCheck %s --check-prefix=ERROR-RELOC
#
# RUN: llvm-objcopy -R .text -R .comdat %t.in.o %t.remove-text-comdat.o
# RUN: llvm-objdump -section-headers %t.remove-text-comdat.o | FileCheck %s --check-prefix=SECTIONS-REMOVE-TEXT-COMDAT
# RUN: llvm-objdump -t %t.remove-text-comdat.o | FileCheck %s --check-prefix=SYMBOLS-REMOVE-TEXT-COMDAT
#
#
# SECTIONS-PRE: Sections:
# SECTIONS-PRE-NEXT: Idx Name
# SECTIONS-PRE-NEXT: 0 .text
# SECTIONS-PRE-NEXT: 1 .bss
# SECTIONS-PRE-NEXT: 2 .comdat
# SECTIONS-PRE-NEXT: 3 .associative
# SECTIONS-PRE-EMPTY:
#
# SYMBOLS-PRE: SYMBOL TABLE:
# SYMBOLS-PRE-NEXT: {{.*}}(sec -1){{.*}} @feat.00
# SYMBOLS-PRE-NEXT: {{.*}}(sec 1){{.*}} .text
# SYMBOLS-PRE-NEXT: AUX scnlen {{.*}} assoc 1 comdat 0
# SYMBOLS-PRE-NEXT: {{.*}}(sec 2){{.*}} .bss
# SYMBOLS-PRE-NEXT: AUX scnlen {{.*}} assoc 2 comdat 0
# SYMBOLS-PRE-NEXT: {{.*}}(sec 4){{.*}} .associative
# SYMBOLS-PRE-NEXT: AUX scnlen {{.*}} assoc 3 comdat 5
# SYMBOLS-PRE-NEXT: {{.*}}(sec 3){{.*}} .comdat
# SYMBOLS-PRE-NEXT: AUX scnlen {{.*}} assoc 3 comdat 2
# SYMBOLS-PRE-NEXT: {{.*}}(sec 3){{.*}} foo
# SYMBOLS-PRE-NEXT: {{.*}}(sec 1){{.*}} main
# SYMBOLS-PRE-EMPTY:
#
#
# Removing the .bss section removes one symbol and its aux symbol,
# and updates the section indices in symbols pointing to later
# symbols, including the aux section defintitions.
#
# Testing that the absolute symbol @feat.00 survives the section number
# mangling.
#
# SECTIONS-REMOVE-BSS: Sections:
# SECTIONS-REMOVE-BSS-NEXT: Idx Name
# SECTIONS-REMOVE-BSS-NEXT: 0 .text
# SECTIONS-REMOVE-BSS-NEXT: 1 .comdat
# SECTIONS-REMOVE-BSS-NEXT: 2 .associative
# SECTIONS-REMOVE-BSS-EMPTY:
#
# SYMBOLS-REMOVE-BSS: SYMBOL TABLE:
# SYMBOLS-REMOVE-BSS-NEXT: {{.*}}(sec -1){{.*}} @feat.00
# SYMBOLS-REMOVE-BSS-NEXT: {{.*}}(sec 1){{.*}} .text
# SYMBOLS-REMOVE-BSS-NEXT: AUX scnlen {{.*}} assoc 1 comdat 0
# SYMBOLS-REMOVE-BSS-NEXT: {{.*}}(sec 3){{.*}} .associative
# SYMBOLS-REMOVE-BSS-NEXT: AUX scnlen {{.*}} assoc 2 comdat 5
# SYMBOLS-REMOVE-BSS-NEXT: {{.*}}(sec 2){{.*}} .comdat
# SYMBOLS-REMOVE-BSS-NEXT: AUX scnlen {{.*}} assoc 2 comdat 2
# SYMBOLS-REMOVE-BSS-NEXT: {{.*}}(sec 2){{.*}} foo
# SYMBOLS-REMOVE-BSS-NEXT: {{.*}}(sec 1){{.*}} main
# SYMBOLS-REMOVE-BSS-EMPTY:
#
#
# Removing the .text section is ok and just removes the external symbol
# referring to it.
#
# SECTIONS-REMOVE-TEXT: Sections:
# SECTIONS-REMOVE-TEXT-NEXT: Idx Name
# SECTIONS-REMOVE-TEXT-NEXT: 0 .bss
# SECTIONS-REMOVE-TEXT-NEXT: 1 .comdat
# SECTIONS-REMOVE-TEXT-NEXT: 2 .associative
# SECTIONS-REMOVE-TEXT-EMPTY:
#
# SYMBOLS-REMOVE-TEXT: SYMBOL TABLE:
# SYMBOLS-REMOVE-TEXT-NEXT: {{.*}}(sec -1){{.*}} @feat.00
# SYMBOLS-REMOVE-TEXT-NEXT: {{.*}}(sec 1){{.*}} .bss
# SYMBOLS-REMOVE-TEXT-NEXT: AUX scnlen {{.*}} assoc 1 comdat 0
# SYMBOLS-REMOVE-TEXT-NEXT: {{.*}}(sec 3){{.*}} .associative
# SYMBOLS-REMOVE-TEXT-NEXT: AUX scnlen {{.*}} assoc 2 comdat 5
# SYMBOLS-REMOVE-TEXT-NEXT: {{.*}}(sec 2){{.*}} .comdat
# SYMBOLS-REMOVE-TEXT-NEXT: AUX scnlen {{.*}} assoc 2 comdat 2
# SYMBOLS-REMOVE-TEXT-NEXT: {{.*}}(sec 2){{.*}} foo
# SYMBOLS-REMOVE-TEXT-EMPTY:
#
#
# Removing the .comdat section fails, since the .text section has relocations
# against it.
#
# ERROR-RELOC: Relocation target foo ({{.*}}) not found
#
#
# Removing the .comdat section and .text (with a relocation against .comdat)
# works, as it also removes the .associative section transitively.
#
# SECTIONS-REMOVE-TEXT-COMDAT: Sections:
# SECTIONS-REMOVE-TEXT-COMDAT-NEXT: Idx Name
# SECTIONS-REMOVE-TEXT-COMDAT-NEXT: 0 .bss
# SECTIONS-REMOVE-TEXT-COMDAT-EMPTY:
#
# SYMBOLS-REMOVE-TEXT-COMDAT: SYMBOL TABLE:
# SYMBOLS-REMOVE-TEXT-COMDAT-NEXT: {{.*}}(sec -1){{.*}} @feat.00
# SYMBOLS-REMOVE-TEXT-COMDAT-NEXT: {{.*}}(sec 1){{.*}} .bss
# SYMBOLS-REMOVE-TEXT-COMDAT-NEXT: AUX scnlen {{.*}} assoc 1 comdat 0
# SYMBOLS-REMOVE-TEXT-COMDAT-EMPTY:

--- !COFF
header:
Machine: IMAGE_FILE_MACHINE_AMD64
Characteristics: [ ]
sections:
- Name: .text
Characteristics: [ ]
Alignment: 4
SectionData: 488B0500000000C3
Relocations:
- VirtualAddress: 3
SymbolName: foo
Type: IMAGE_REL_AMD64_REL32
- Name: .bss
Characteristics: [ ]
Alignment: 4
SectionData: ''
- Name: .comdat
Characteristics: [ IMAGE_SCN_LNK_COMDAT ]
Alignment: 1
SectionData: '2A000000'
- Name: .associative
Characteristics: [ IMAGE_SCN_LNK_COMDAT ]
Alignment: 1
SectionData: '0000000000000000'
symbols:
- Name: '@feat.00'
Value: 0
SectionNumber: -1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- Name: .text
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
SectionDefinition:
Length: 8
NumberOfRelocations: 1
NumberOfLinenumbers: 0
CheckSum: 583624169
Number: 1
- Name: .bss
Value: 0
SectionNumber: 2
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
SectionDefinition:
Length: 0
NumberOfRelocations: 0
NumberOfLinenumbers: 0
CheckSum: 0
Number: 2
- Name: .associative
Value: 0
SectionNumber: 4
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
SectionDefinition:
Length: 8
NumberOfRelocations: 0
NumberOfLinenumbers: 0
CheckSum: 0
Number: 3
Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
- Name: .comdat
Value: 0
SectionNumber: 3
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
SectionDefinition:
Length: 4
NumberOfRelocations: 0
NumberOfLinenumbers: 0
CheckSum: 3482275674
Number: 3
Selection: IMAGE_COMDAT_SELECT_ANY
- Name: foo
Value: 0
SectionNumber: 3
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
- Name: main
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
...
10 changes: 9 additions & 1 deletion llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
Expand Up @@ -27,9 +27,17 @@ using namespace object;
using namespace COFF;

static Error handleArgs(const CopyConfig &Config, Object &Obj) {
// Perform the actual section removals.
Obj.removeSections([&Config](const Section &Sec) {
if (is_contained(Config.ToRemove, Sec.Name))
return true;

return false;
});

// StripAll removes all symbols and thus also removes all relocations.
if (Config.StripAll || Config.StripAllGNU)
for (Section &Sec : Obj.Sections)
for (Section &Sec : Obj.getMutableSections())
Sec.Relocs.clear();

// If we need to do per-symbol removals, initialize the Referenced field.
Expand Down
63 changes: 63 additions & 0 deletions llvm/tools/llvm-objcopy/COFF/Object.cpp
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "Object.h"
#include "llvm/ADT/DenseSet.h"
#include <algorithm>

namespace llvm {
Expand Down Expand Up @@ -64,6 +65,68 @@ Error Object::markSymbols() {
return Error::success();
}

void Object::addSections(ArrayRef<Section> NewSections) {
for (Section S : NewSections) {
S.UniqueId = NextSectionUniqueId++;
Sections.emplace_back(S);
}
updateSections();
}

void Object::updateSections() {
SectionMap = DenseMap<ssize_t, Section *>(Sections.size());
size_t Index = 1;
for (Section &S : Sections) {
SectionMap[S.UniqueId] = &S;
S.Index = Index++;
}
}

const Section *Object::findSection(ssize_t UniqueId) const {
auto It = SectionMap.find(UniqueId);
if (It == SectionMap.end())
return nullptr;
return It->second;
}

void Object::removeSections(function_ref<bool(const Section &)> ToRemove) {
DenseSet<ssize_t> AssociatedSections;
auto RemoveAssociated = [&AssociatedSections](const Section &Sec) {
return AssociatedSections.count(Sec.UniqueId) == 1;
};
do {
DenseSet<ssize_t> RemovedSections;
Sections.erase(
std::remove_if(std::begin(Sections), std::end(Sections),
[ToRemove, &RemovedSections](const Section &Sec) {
bool Remove = ToRemove(Sec);
if (Remove)
RemovedSections.insert(Sec.UniqueId);
return Remove;
}),
std::end(Sections));
// Remove all symbols referring to the removed sections.
AssociatedSections.clear();
Symbols.erase(
std::remove_if(
std::begin(Symbols), std::end(Symbols),
[&RemovedSections, &AssociatedSections](const Symbol &Sym) {
// If there are sections that are associative to a removed
// section,
// remove those as well as nothing will include them (and we can't
// leave them dangling).
if (RemovedSections.count(Sym.AssociativeComdatTargetSectionId) ==
1)
AssociatedSections.insert(Sym.TargetSectionId);
return RemovedSections.count(Sym.TargetSectionId) == 1;
}),
std::end(Symbols));
ToRemove = RemoveAssociated;
} while (!AssociatedSections.empty());
updateSections();
updateSymbols();
}

} // end namespace coff
} // end namespace objcopy
} // end namespace llvm
27 changes: 25 additions & 2 deletions llvm/tools/llvm-objcopy/COFF/Object.h
Expand Up @@ -37,12 +37,16 @@ struct Section {
ArrayRef<uint8_t> Contents;
std::vector<Relocation> Relocs;
StringRef Name;
ssize_t UniqueId;
size_t Index;
};

struct Symbol {
object::coff_symbol32 Sym;
StringRef Name;
ArrayRef<uint8_t> AuxData;
std::vector<uint8_t> AuxData;
ssize_t TargetSectionId;
ssize_t AssociativeComdatTargetSectionId = 0;
size_t UniqueId;
size_t RawIndex;
bool Referenced;
Expand All @@ -61,7 +65,6 @@ struct Object {
uint32_t BaseOfData = 0; // pe32plus_header lacks this field.

std::vector<object::data_directory> DataDirectories;
std::vector<Section> Sections;

ArrayRef<Symbol> getSymbols() const { return Symbols; }
// This allows mutating individual Symbols, but not mutating the list
Expand All @@ -79,14 +82,34 @@ struct Object {
// all sections.
Error markSymbols();

ArrayRef<Section> getSections() const { return Sections; }
// This allows mutating individual Sections, but not mutating the list
// of symbols itself.
iterator_range<std::vector<Section>::iterator> getMutableSections() {
return make_range(Sections.begin(), Sections.end());
}

const Section *findSection(ssize_t UniqueId) const;

void addSections(ArrayRef<Section> NewSections);
void removeSections(function_ref<bool(const Section &)> ToRemove);

private:
std::vector<Symbol> Symbols;
DenseMap<size_t, Symbol *> SymbolMap;

size_t NextSymbolUniqueId = 0;

std::vector<Section> Sections;
DenseMap<ssize_t, Section *> SectionMap;

ssize_t NextSectionUniqueId = 1; // Allow a UniqueId 0 to mean undefined.

// Update SymbolMap and RawIndex in each Symbol.
void updateSymbols();

// Update SectionMap and Index in each Section.
void updateSections();
};

// Copy between coff_symbol16 and coff_symbol32.
Expand Down

0 comments on commit f9e1434

Please sign in to comment.