[llvm-objcopy][MachO] Skip sections with zero offset

Some binaries can contain regular sections with zero offset and zero size.
This diff makes llvm-objcopy's handling of such sections consistent with
cctools's strip (which doesn't modify them),
previously the tool would allocate file space for them.

Test plan: make check-all

Differential revision: https://reviews.llvm.org/D90796
This commit is contained in:
Alexander Shaposhnikov 2020-11-06 13:10:41 -08:00
parent 2993850237
commit f147f59cd3
5 changed files with 61 additions and 6 deletions

View File

@ -0,0 +1,43 @@
## This test verifies that a regular (non-zero-fill) section with zero offset
## and zero size is not modifed, this behavior is consistent with cctools' strip.
# RUN: yaml2obj %s -o %t
# RUN: llvm-objcopy %t %t.copy
# RUN: cmp %t %t.copy
--- !mach-o
FileHeader:
magic: 0xFEEDFACE
cputype: 0x00000007
cpusubtype: 0x00000003
filetype: 0x00000001
ncmds: 1
sizeofcmds: 124
flags: 0x00002000
LoadCommands:
- cmd: LC_SEGMENT
cmdsize: 124
segname: __DATA
vmaddr: 4096
vmsize: 0
fileoff: 152
filesize: 0
maxprot: 7
initprot: 7
nsects: 1
flags: 0
Sections:
- sectname: __broken
segname: __DATA
addr: 0x0000000000001000
size: 0
offset: 0x00000000
align: 2
reloff: 0x00000000
nreloc: 0
flags: 0x00000000
reserved1: 0x00000000
reserved2: 0x00000000
reserved3: 0x00000000
content: ''
...

View File

@ -148,7 +148,7 @@ uint64_t MachOLayoutBuilder::layoutSegments() {
"Section's address cannot be smaller than Segment's one");
uint32_t SectOffset = Sec->Addr - SegmentVmAddr;
if (IsObjectFile) {
if (Sec->isVirtualSection()) {
if (!Sec->hasValidOffset()) {
Sec->Offset = 0;
} else {
uint64_t PaddingSize =
@ -158,7 +158,7 @@ uint64_t MachOLayoutBuilder::layoutSegments() {
SegFileSize += PaddingSize + Sec->Size;
}
} else {
if (Sec->isVirtualSection()) {
if (!Sec->hasValidOffset()) {
Sec->Offset = 0;
} else {
Sec->Offset = SegOffset + SectOffset;

View File

@ -35,7 +35,7 @@ Section constructSectionCommon(SectionType Sec, uint32_t Index) {
S.Index = Index;
S.Addr = Sec.addr;
S.Size = Sec.size;
S.Offset = Sec.offset;
S.OriginalOffset = Sec.offset;
S.Align = Sec.align;
S.RelOff = Sec.reloff;
S.NReloc = Sec.nreloc;

View File

@ -121,8 +121,10 @@ size_t MachOWriter::totalSize() const {
// Otherwise, use the last section / reloction.
for (const LoadCommand &LC : O.LoadCommands)
for (const std::unique_ptr<Section> &S : LC.Sections) {
if (S->isVirtualSection()) {
assert((S->Offset == 0) && "Zero-fill section's offset must be zero");
if (!S->hasValidOffset()) {
assert((S->Offset == 0) && "Skipped section's offset must be zero");
assert((S->isVirtualSection() || S->Size == 0) &&
"Non-zero-fill sections with zero offset must have zero size");
continue;
}
assert((S->Offset != 0) &&
@ -246,8 +248,12 @@ void MachOWriter::writeSectionInLoadCommand(const Section &Sec, uint8_t *&Out) {
void MachOWriter::writeSections() {
for (const LoadCommand &LC : O.LoadCommands)
for (const std::unique_ptr<Section> &Sec : LC.Sections) {
if (Sec->isVirtualSection())
if (!Sec->hasValidOffset()) {
assert((Sec->Offset == 0) && "Skipped section's offset must be zero");
assert((Sec->isVirtualSection() || Sec->Size == 0) &&
"Non-zero-fill sections with zero offset must have zero size");
continue;
}
assert(Sec->Offset && "Section offset can not be zero");
assert((Sec->Size == Sec->Content.size()) && "Incorrect section size");

View File

@ -44,6 +44,8 @@ struct Section {
std::string CanonicalName;
uint64_t Addr = 0;
uint64_t Size = 0;
// Offset in the input file.
Optional<uint32_t> OriginalOffset;
uint32_t Offset = 0;
uint32_t Align = 0;
uint32_t RelOff = 0;
@ -73,6 +75,10 @@ struct Section {
getType() == MachO::S_GB_ZEROFILL ||
getType() == MachO::S_THREAD_LOCAL_ZEROFILL);
}
bool hasValidOffset() const {
return !(isVirtualSection() || (OriginalOffset && *OriginalOffset == 0));
}
};
struct LoadCommand {