diff --git a/llvm/test/tools/llvm-objcopy/COFF/update-section.test b/llvm/test/tools/llvm-objcopy/COFF/update-section.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/COFF/update-section.test @@ -0,0 +1,72 @@ +# RUN: echo -n AAAB > %t.diff +# RUN: echo -n AAA > %t.smaller +# RUN: echo -n AAAAA > %t.larger + +# RUN: yaml2obj %s -o %t + +# RUN: llvm-objcopy --update-section=.text=%t.diff %t - | llvm-readobj -S -x .text - | FileCheck %s +# CHECK: Section { +# CHECK-NEXT: Number: 1 +# CHECK-NEXT: Name: .text +# CHECK-NOT: } +# CHECK: RawDataSize: 4 +# CHECK: Hex dump of section '.text': +# CHECK-NEXT: 0x00000000 41414142 AAAB + +# RUN: llvm-objcopy --update-section=.text=%t.smaller %t - | llvm-readobj -S -x .text - | FileCheck %s --check-prefix=SMALLER +# SMALLER: Section { +# SMALLER-NEXT: Number: 1 +# SMALLER-NEXT: Name: .text +# SMALLER-NOT: } +# SMALLER: RawDataSize: 3 +# SMALLER: Hex dump of section '.text': +# SMALLER-NEXT: 0x00000000 414141 AAA + +# RUN: llvm-objcopy --update-section=.text=%t.diff --update-section=.other=%t.diff %t - | \ +# RUN: llvm-readobj -S -x .text -x .other - | FileCheck %s --check-prefix=MULTIPLE +# MULTIPLE: Section { +# MULTIPLE-NEXT: Number: 1 +# MULTIPLE-NEXT: Name: .text +# MULTIPLE-NOT: } +# MULTIPLE: RawDataSize: 4 +# MULTIPLE: Section { +# MULTIPLE-NEXT: Number: 2 +# MULTIPLE-NEXT: Name: .other +# MULTIPLE-NOT: } +# MULTIPLE: RawDataSize: 4 +# MULTIPLE: Hex dump of section '.text': +# MULTIPLE-NEXT: 0x00000000 41414142 AAAB +# MULTIPLE: Hex dump of section '.other': +# MULTIPLE-NEXT: 0x00000000 41414142 AAAB + +# RUN: not llvm-objcopy --update-section=.text=%t.larger %t /dev/null 2>&1 | FileCheck %s --check-prefix=TOO-LARGE +# TOO-LARGE: error: {{.*}}new section cannot be larger than previous section + +# RUN: not llvm-objcopy --update-section=.bss=%t.diff %t /dev/null 2>&1 | FileCheck %s --check-prefix=NO-CONTENTS +# NO-CONTENTS: error: {{.*}}section '.bss' cannot be updated because it does not have contents + +# RUN: not llvm-objcopy --update-section=.text=%t.noexist %t /dev/null 2>&1 | \ +# RUN: FileCheck %s --check-prefix=NOENT -DENOENT=%errc_ENOENT +# NOENT: error: {{.*}}: [[ENOENT]] + +# RUN: not llvm-objcopy --update-section=.noexist=%t.diff %t /dev/null 2>&1 | FileCheck %s --check-prefix=NO-SECTION +# NO-SECTION: error: {{.*}}could not find section with name '.noexist' + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ ] + Alignment: 4 + SectionData: '41414141' + - Name: .other + Characteristics: [ ] + Alignment: 4 + SectionData: '42424242' + - Name: .bss + Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA ] + SizeOfRawData: 0 +symbols: +... diff --git a/llvm/test/tools/llvm-objcopy/ELF/update-section.test b/llvm/test/tools/llvm-objcopy/ELF/update-section.test --- a/llvm/test/tools/llvm-objcopy/ELF/update-section.test +++ b/llvm/test/tools/llvm-objcopy/ELF/update-section.test @@ -170,8 +170,8 @@ # ADD-UPDATE: ) # ERR-NO-SECTION: error: {{.*}}section '.nosection' not found -# ERR-NOBITS-TYPE: error: {{.*}}section '.nobits_type' can't be updated because it does not have contents -# ERR-NULL-TYPE: error: {{.*}}section '.null_type' can't be updated because it does not have contents +# ERR-NOBITS-TYPE: error: {{.*}}section '.nobits_type' cannot be updated because it does not have contents +# ERR-NULL-TYPE: error: {{.*}}section '.null_type' cannot be updated because it does not have contents # ERR-LARGER: error: {{.*}}cannot fit data of size 9 into section '.in_segment' with size 8 that is part of a segment # MISSING-EQ: error: bad format for --update-section: missing '=' diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp --- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp @@ -253,6 +253,35 @@ Characteristics); } + for (StringRef Flag : Config.UpdateSection) { + StringRef SecName, FileName; + std::tie(SecName, FileName) = Flag.split('='); + + auto BufOrErr = MemoryBuffer::getFile(FileName); + if (!BufOrErr) + return createFileError(FileName, errorCodeToError(BufOrErr.getError())); + auto Buf = std::move(*BufOrErr); + + auto It = llvm::find_if(Obj.getMutableSections(), [SecName](auto &Sec) { + return Sec.Name == SecName; + }); + if (It == Obj.getMutableSections().end()) + return createStringError(errc::invalid_argument, + "could not find section with name '%s'", + SecName.str().c_str()); + size_t ContentSize = It->getContents().size(); + if (!ContentSize) + return createStringError( + errc::invalid_argument, + "section '%s' cannot be updated because it does not have contents", + SecName.str().c_str()); + if (ContentSize < Buf->getBufferSize()) + return createStringError( + errc::invalid_argument, + "new section cannot be larger than previous section"); + It->setOwnedContents({Buf->getBufferStart(), Buf->getBufferEnd()}); + } + if (!Config.AddGnuDebugLink.empty()) if (Error E = addGnuDebugLink(Obj, Config.AddGnuDebugLink)) return E; diff --git a/llvm/tools/llvm-objcopy/COFF/Object.h b/llvm/tools/llvm-objcopy/COFF/Object.h --- a/llvm/tools/llvm-objcopy/COFF/Object.h +++ b/llvm/tools/llvm-objcopy/COFF/Object.h @@ -54,6 +54,7 @@ void setOwnedContents(std::vector &&Data) { ContentsRef = ArrayRef(); OwnedContents = std::move(Data); + Header.SizeOfRawData = OwnedContents.size(); } void clearContents() { diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp --- a/llvm/tools/llvm-objcopy/ELF/Object.cpp +++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp @@ -2156,7 +2156,7 @@ if (!OldSec->hasContents()) return createStringError( errc::invalid_argument, - "section '%s' can't be updated because it does not have contents", + "section '%s' cannot be updated because it does not have contents", Name.str().c_str()); if (Data.size() > OldSec->Size && OldSec->ParentSegment)