diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -165,6 +165,7 @@ bool ltoNewPassManager; bool mergeArmExidx; bool mipsN32Abi = false; + bool mmapOutputFile; bool nmagic; bool noinhibitExec; bool nostdlib; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -886,6 +886,8 @@ config->mipsGotSize = args::getInteger(args, OPT_mips_got_size, 0xfff0); config->mergeArmExidx = args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true); + config->mmapOutputFile = + args.hasFlag(OPT_mmap_output_file, OPT_no_mmap_output_file, true); config->nmagic = args.hasFlag(OPT_nmagic, OPT_no_nmagic, false); config->noinhibitExec = args.hasArg(OPT_noinhibit_exec); config->nostdlib = args.hasArg(OPT_nostdlib); diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -232,6 +232,10 @@ "Enable merging .ARM.exidx entries (default)", "Disable merging .ARM.exidx entries">; +defm mmap_output_file: B<"mmap-output-file", + "Mmap the output file for writing (default)", + "Do not mmap the output file for writing">; + def nmagic: F<"nmagic">, MetaVarName<"">, HelpText<"Do not page align sections, link against static libraries.">; @@ -566,7 +570,6 @@ def: F<"no-copy-dt-needed-entries">; def: F<"no-ctors-in-init-array">; def: F<"no-keep-memory">; -def: F<"no-mmap-output-file">; def: F<"no-pipeline-knowledge">; def: F<"no-warn-mismatch">; def: Flag<["-"], "p">; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -2594,6 +2594,8 @@ unsigned flags = 0; if (!config->relocatable) flags = FileOutputBuffer::F_executable; + if (!config->mmapOutputFile) + flags |= FileOutputBuffer::F_no_mmap; Expected> bufferOrErr = FileOutputBuffer::create(config->outputFile, fileSize, flags); diff --git a/lld/test/ELF/mmap-output-file.s b/lld/test/ELF/mmap-output-file.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/mmap-output-file.s @@ -0,0 +1,12 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t +# RUN: ld.lld %t.o -mmap-output-file -o %t1 +# RUN: cmp %t %t1 +# RUN: ld.lld %t.o -no-mmap-output-file -o %t2 +# RUN: cmp %t %t2 + +.globl _start +_start: + nop diff --git a/lld/test/ELF/silent-ignore.test b/lld/test/ELF/silent-ignore.test --- a/lld/test/ELF/silent-ignore.test +++ b/lld/test/ELF/silent-ignore.test @@ -6,7 +6,6 @@ RUN: -no-copy-dt-needed-entries \ RUN: -no-ctors-in-init-array \ RUN: -no-keep-memory \ -RUN: -no-mmap-output-file \ RUN: -no-pipeline-knowledge \ RUN: -no-warn-mismatch \ RUN: -p \ diff --git a/llvm/include/llvm/Support/FileOutputBuffer.h b/llvm/include/llvm/Support/FileOutputBuffer.h --- a/llvm/include/llvm/Support/FileOutputBuffer.h +++ b/llvm/include/llvm/Support/FileOutputBuffer.h @@ -32,6 +32,10 @@ enum { /// set the 'x' bit on the resulting file F_executable = 1, + + /// Don't use mmap and instead write an in-memory buffer to a file when this + /// buffer is closed. + F_no_mmap = 2, }; /// Factory method to create an OutputBuffer object which manages a read/write diff --git a/llvm/lib/Support/FileOutputBuffer.cpp b/llvm/lib/Support/FileOutputBuffer.cpp --- a/llvm/lib/Support/FileOutputBuffer.cpp +++ b/llvm/lib/Support/FileOutputBuffer.cpp @@ -189,7 +189,10 @@ case fs::file_type::regular_file: case fs::file_type::file_not_found: case fs::file_type::status_error: - return createOnDiskBuffer(Path, Size, Mode); + if (Flags & F_no_mmap) + return createInMemoryBuffer(Path, Size, Mode); + else + return createOnDiskBuffer(Path, Size, Mode); default: return createInMemoryBuffer(Path, Size, Mode); } diff --git a/llvm/unittests/Support/FileOutputBufferTest.cpp b/llvm/unittests/Support/FileOutputBufferTest.cpp --- a/llvm/unittests/Support/FileOutputBufferTest.cpp +++ b/llvm/unittests/Support/FileOutputBufferTest.cpp @@ -118,6 +118,28 @@ EXPECT_TRUE(IsExecutable); ASSERT_NO_ERROR(fs::remove(File4.str())); + // TEST 5: In-memory buffer works as expected. + SmallString<128> File5(TestDirectory); + File5.append("/file5"); + { + Expected> BufferOrErr = + FileOutputBuffer::create(File5, 8000, FileOutputBuffer::F_no_mmap); + ASSERT_NO_ERROR(errorToErrorCode(BufferOrErr.takeError())); + std::unique_ptr &Buffer = *BufferOrErr; + // Start buffer with special header. + memcpy(Buffer->getBufferStart(), "AABBCCDDEEFFGGHHIIJJ", 20); + ASSERT_NO_ERROR(errorToErrorCode(Buffer->commit())); + // Write to end of buffer to verify it is writable. + memcpy(Buffer->getBufferEnd() - 20, "AABBCCDDEEFFGGHHIIJJ", 20); + // Commit buffer. + ASSERT_NO_ERROR(errorToErrorCode(Buffer->commit())); + } + + // Verify file is correct size. + uint64_t File5Size; + ASSERT_NO_ERROR(fs::file_size(Twine(File5), File5Size)); + ASSERT_EQ(File5Size, 8000ULL); + ASSERT_NO_ERROR(fs::remove(File5.str())); // Clean up. ASSERT_NO_ERROR(fs::remove(TestDirectory.str())); }