Index: llvm/test/tools/llvm-objcopy/ELF/binary-output-empty.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-objcopy/ELF/binary-output-empty.test @@ -0,0 +1,26 @@ +# RUN: yaml2obj %s -o %t.o + +# Writing an empty output to a non-existant file will still create it. +# RUN: rm -f %t-new.txt +# RUN: llvm-objcopy -R .text -O binary %t.o %t-new.txt +# RUN: wc -c %t-new.txt | FileCheck %s + +# Writing an empty output to an existing file will truncate it. +# RUN: echo abcd > %t-existing.txt +# RUN: llvm-objcopy -R .text -O binary %t.o %t-existing.txt +# RUN: wc -c %t-existing.txt | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Content: "c3c3c3c3" + Size: 0x1000 + +# CHECK: 0 Index: llvm/tools/llvm-objcopy/Buffer.cpp =================================================================== --- llvm/tools/llvm-objcopy/Buffer.cpp +++ llvm/tools/llvm-objcopy/Buffer.cpp @@ -10,7 +10,9 @@ #include "Buffer.h" #include "llvm-objcopy.h" #include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Process.h" #include namespace llvm { @@ -19,15 +21,27 @@ Buffer::~Buffer() {} void FileBuffer::allocate(size_t Size) { - Expected> BufferOrErr = - FileOutputBuffer::create(getName(), Size, FileOutputBuffer::F_executable); - handleAllErrors(BufferOrErr.takeError(), [this](const ErrorInfoBase &E) { - error("failed to open " + getName() + ": " + E.message()); - }); - Buf = std::move(*BufferOrErr); + // Only create a buffer if we have a positive size. Otherwise, create (and + // truncate) the file. + if (Size > 0) { + Expected> BufferOrErr = + FileOutputBuffer::create(getName(), Size, + FileOutputBuffer::F_executable); + handleAllErrors(BufferOrErr.takeError(), [this](const ErrorInfoBase &E) { + error("failed to open " + getName() + ": " + E.message()); + }); + Buf = std::move(*BufferOrErr); + } else { + int FD; + if (std::error_code EC = sys::fs::openFileForWrite( + getName(), FD, sys::fs::CD_CreateAlways, sys::fs::OF_None)) + reportError(getName(), EC); + if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD)) + reportError(getName(), EC); + } } -Error FileBuffer::commit() { return Buf->commit(); } +Error FileBuffer::commit() { return Buf ? Buf->commit() : Error::success(); } uint8_t *FileBuffer::getBufferStart() { return reinterpret_cast(Buf->getBufferStart());