diff --git a/CMakeLists.txt b/CMakeLists.txt index b4396fd4b3..60902c5e6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -334,9 +334,15 @@ else() endif() if(WIN32) - list(APPEND MOLD_ELF_TEMPLATE_FILES src/subprocess-win32.cc) + list(APPEND MOLD_ELF_TEMPLATE_FILES + src/output-file-win32.cc + src/subprocess-win32.cc + ) else() - list(APPEND MOLD_ELF_TEMPLATE_FILES src/subprocess-unix.cc) + list(APPEND MOLD_ELF_TEMPLATE_FILES + src/output-file-unix.cc + src/subprocess-unix.cc + ) endif() function(mold_instantiate_templates SOURCE TARGET) diff --git a/lib/common.h b/lib/common.h index c27072410d..cfa9e9b547 100644 --- a/lib/common.h +++ b/lib/common.h @@ -525,15 +525,6 @@ inline void overwrite_uleb(u8 *loc, u64 val) { *loc = val & 0b0111'1111; } -template -std::string_view save_string(Context &ctx, const std::string &str) { - u8 *buf = new u8[str.size() + 1]; - memcpy(buf, str.data(), str.size()); - buf[str.size()] = '\0'; - ctx.string_pool.push_back(std::unique_ptr(buf)); - return {(char *)buf, str.size()}; -} - static inline void pause() { #if defined(__x86_64__) asm volatile("pause"); @@ -718,82 +709,6 @@ class ConcurrentMap { void get_random_bytes(u8 *buf, i64 size); -// -// output-file.h -// - -template -class OutputFile { -public: - static std::unique_ptr> - open(Context &ctx, std::string path, i64 filesize, int perm); - - virtual void close(Context &ctx) = 0; - virtual ~OutputFile() = default; - - u8 *buf = nullptr; - std::vector buf2; - std::string path; - int fd = -1; - i64 filesize = 0; - bool is_mmapped = false; - bool is_unmapped = false; - -protected: - OutputFile(std::string path, i64 filesize, bool is_mmapped) - : path(path), filesize(filesize), is_mmapped(is_mmapped) {} -}; - -template -class MallocOutputFile : public OutputFile { -public: - MallocOutputFile(Context &ctx, std::string path, i64 filesize, int perm) - : OutputFile(path, filesize, false), ptr(new u8[filesize]), - perm(perm) { - this->buf = ptr.get(); - } - - void close(Context &ctx) override { - Timer t(ctx, "close_file"); - FILE *fp; - - if (this->path == "-") { - fp = stdout; - } else { -#ifdef _WIN32 - int pmode = (perm & 0200) ? (_S_IREAD | _S_IWRITE) : _S_IREAD; - i64 fd = _open(this->path.c_str(), _O_RDWR | _O_CREAT | _O_BINARY, pmode); -#else - i64 fd = ::open(this->path.c_str(), O_RDWR | O_CREAT, perm); -#endif - if (fd == -1) - Fatal(ctx) << "cannot open " << this->path << ": " << errno_string(); -#ifdef _WIN32 - fp = _fdopen(fd, "wb"); -#else - fp = fdopen(fd, "w"); -#endif - } - - fwrite(this->buf, this->filesize, 1, fp); - if (!this->buf2.empty()) - fwrite(this->buf2.data(), this->buf2.size(), 1, fp); - fclose(fp); - } - -private: - std::unique_ptr ptr; - int perm; -}; - -template -class LockingOutputFile : public OutputFile { -public: - LockingOutputFile(Context &ctx, std::string path, int perm); - void resize(Context &ctx, i64 filesize); - void close(Context &ctx) override; -}; - // // hyperloglog.cc // diff --git a/lib/output-file.h b/lib/output-file.h deleted file mode 100644 index 63299ed998..0000000000 --- a/lib/output-file.h +++ /dev/null @@ -1,5 +0,0 @@ -#if _WIN32 -# include "output-file-win32.h" -#else -# include "output-file-unix.h" -#endif diff --git a/src/main.cc b/src/main.cc index 2dc4c8235b..0115c596c3 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,7 +1,6 @@ #include "mold.h" #include "filetype.h" #include "../lib/archive-file.h" -#include "../lib/output-file.h" #include #include @@ -655,8 +654,7 @@ int mold_main(int argc, char **argv) { t_before_copy.stop(); // Create an output file - ctx.output_file = - OutputFile>::open(ctx, ctx.arg.output, filesize, 0777); + ctx.output_file = OutputFile::open(ctx, ctx.arg.output, filesize, 0777); ctx.buf = ctx.output_file->buf; Timer t_copy(ctx, "copy"); diff --git a/src/mold.h b/src/mold.h index 4149f045ba..b95710dfdf 100644 --- a/src/mold.h +++ b/src/mold.h @@ -1074,6 +1074,82 @@ class ComdatGroupSection : public Chunk { std::vector *> members; }; +// +// output-file.cc +// + +template +class OutputFile { +public: + static std::unique_ptr> + open(Context &ctx, std::string path, i64 filesize, int perm); + + virtual void close(Context &ctx) = 0; + virtual ~OutputFile() = default; + + u8 *buf = nullptr; + std::vector buf2; + std::string path; + int fd = -1; + i64 filesize = 0; + bool is_mmapped = false; + bool is_unmapped = false; + +protected: + OutputFile(std::string path, i64 filesize, bool is_mmapped) + : path(path), filesize(filesize), is_mmapped(is_mmapped) {} +}; + +template +class MallocOutputFile : public OutputFile { +public: + MallocOutputFile(Context &ctx, std::string path, i64 filesize, int perm) + : OutputFile(path, filesize, false), ptr(new u8[filesize]), + perm(perm) { + this->buf = ptr.get(); + } + + void close(Context &ctx) override { + Timer t(ctx, "close_file"); + FILE *fp; + + if (this->path == "-") { + fp = stdout; + } else { +#ifdef _WIN32 + int pmode = (perm & 0200) ? (_S_IREAD | _S_IWRITE) : _S_IREAD; + i64 fd = _open(this->path.c_str(), _O_RDWR | _O_CREAT | _O_BINARY, pmode); +#else + i64 fd = ::open(this->path.c_str(), O_RDWR | O_CREAT, perm); +#endif + if (fd == -1) + Fatal(ctx) << "cannot open " << this->path << ": " << errno_string(); +#ifdef _WIN32 + fp = _fdopen(fd, "wb"); +#else + fp = fdopen(fd, "w"); +#endif + } + + fwrite(this->buf, this->filesize, 1, fp); + if (!this->buf2.empty()) + fwrite(this->buf2.data(), this->buf2.size(), 1, fp); + fclose(fp); + } + +private: + std::unique_ptr ptr; + int perm; +}; + +template +class LockingOutputFile : public OutputFile { +public: + LockingOutputFile(Context &ctx, std::string path, int perm); + void resize(Context &ctx, i64 filesize); + void close(Context &ctx) override; +}; + // // gdb-index.cc // @@ -1956,7 +2032,7 @@ struct Context { std::vector> internal_esyms; // Output buffer - std::unique_ptr>> output_file; + std::unique_ptr> output_file; u8 *buf = nullptr; bool overwrite_output_file = true; @@ -3021,4 +3097,13 @@ inline bool is_c_identifier(std::string_view s) { return true; } +template +std::string_view save_string(Context &ctx, const std::string &str) { + u8 *buf = new u8[str.size() + 1]; + memcpy(buf, str.data(), str.size()); + buf[str.size()] = '\0'; + ctx.string_pool.push_back(std::unique_ptr(buf)); + return {(char *)buf, str.size()}; +} + } // namespace mold diff --git a/lib/output-file-unix.h b/src/output-file-unix.cc similarity index 83% rename from lib/output-file-unix.h rename to src/output-file-unix.cc index dcbebfb3f0..0a6f9eb28a 100644 --- a/lib/output-file-unix.h +++ b/src/output-file-unix.cc @@ -1,4 +1,4 @@ -#include "common.h" +#include "mold.h" #include #include @@ -9,15 +9,15 @@ namespace mold { -inline u32 get_umask() { +static u32 get_umask() { u32 orig_umask = umask(0); umask(orig_umask); return orig_umask; } -template +template static int -open_or_create_file(Context &ctx, std::string path, std::string tmpfile, +open_or_create_file(Context &ctx, std::string path, std::string tmpfile, int perm) { // Reuse an existing file if exists and writable because on Linux, // writing to an existing file is much faster than creating a fresh @@ -35,11 +35,11 @@ open_or_create_file(Context &ctx, std::string path, std::string tmpfile, return fd; } -template -class MemoryMappedOutputFile : public OutputFile { +template +class MemoryMappedOutputFile : public OutputFile { public: - MemoryMappedOutputFile(Context &ctx, std::string path, i64 filesize, int perm) - : OutputFile(path, filesize, true) { + MemoryMappedOutputFile(Context &ctx, std::string path, i64 filesize, int perm) + : OutputFile(path, filesize, true) { std::filesystem::path dir = filepath(path).parent_path(); std::string filename = filepath(path).filename().string(); std::string tmpfile = dir / ("." + filename + "." + std::to_string(getpid())); @@ -72,7 +72,7 @@ class MemoryMappedOutputFile : public OutputFile { ::close(fd2); } - void close(Context &ctx) override { + void close(Context &ctx) override { Timer t(ctx, "close_file"); if (!this->is_unmapped) @@ -103,9 +103,9 @@ class MemoryMappedOutputFile : public OutputFile { int fd2 = -1; }; -template -std::unique_ptr> -OutputFile::open(Context &ctx, std::string path, i64 filesize, int perm) { +template +std::unique_ptr> +OutputFile::open(Context &ctx, std::string path, i64 filesize, int perm) { Timer t(ctx, "open_file"); if (path.starts_with('/') && !ctx.arg.chroot.empty()) @@ -120,7 +120,7 @@ OutputFile::open(Context &ctx, std::string path, i64 filesize, int perm is_special = true; } - OutputFile *file; + OutputFile *file; if (is_special) file = new MallocOutputFile(ctx, path, filesize, perm); else @@ -146,10 +146,10 @@ OutputFile::open(Context &ctx, std::string path, i64 filesize, int perm // LockingOutputFile is similar to MemoryMappedOutputFile, but it doesn't // rename output files and instead acquires file lock using flock(). -template -LockingOutputFile::LockingOutputFile(Context &ctx, std::string path, - int perm) - : OutputFile(path, 0, true) { +template +LockingOutputFile::LockingOutputFile(Context &ctx, std::string path, + int perm) + : OutputFile(path, 0, true) { this->fd = ::open(path.c_str(), O_RDWR | O_CREAT, perm); if (this->fd == -1) Fatal(ctx) << "cannot open " << path << ": " << errno_string(); @@ -162,8 +162,8 @@ LockingOutputFile::LockingOutputFile(Context &ctx, std::string path, (void)!!write(this->fd, buf, sizeof(buf)); } -template -void LockingOutputFile::resize(Context &ctx, i64 filesize) { +template +void LockingOutputFile::resize(Context &ctx, i64 filesize) { if (ftruncate(this->fd, filesize) == -1) Fatal(ctx) << "ftruncate failed: " << errno_string(); @@ -177,8 +177,8 @@ void LockingOutputFile::resize(Context &ctx, i64 filesize) { mold::output_buffer_end = this->buf + filesize; } -template -void LockingOutputFile::close(Context &ctx) { +template +void LockingOutputFile::close(Context &ctx) { if (!this->is_unmapped) munmap(this->buf, this->filesize); @@ -192,4 +192,9 @@ void LockingOutputFile::close(Context &ctx) { ::close(this->fd); } +using E = MOLD_TARGET; + +template class OutputFile; +template class LockingOutputFile; + } // namespace mold diff --git a/lib/output-file-win32.h b/src/output-file-win32.cc similarity index 74% rename from lib/output-file-win32.h rename to src/output-file-win32.cc index 5e37fb47a1..68bd26c8a5 100644 --- a/lib/output-file-win32.h +++ b/src/output-file-win32.cc @@ -1,4 +1,4 @@ -#include "common.h" +#include "mold.h" #include #include @@ -6,11 +6,11 @@ namespace mold { -template -class MemoryMappedOutputFile : public OutputFile { +template +class MemoryMappedOutputFile : public OutputFile { public: - MemoryMappedOutputFile(Context &ctx, std::string path, i64 filesize, int perm) - : OutputFile(path, filesize, true) { + MemoryMappedOutputFile(Context &ctx, std::string path, i64 filesize, int perm) + : OutputFile(path, filesize, true) { // TODO: use intermediate temporary file for output. DWORD attrs = (perm & 0200) ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_READONLY; @@ -40,7 +40,7 @@ class MemoryMappedOutputFile : public OutputFile { CloseHandle(handle); } - void close(Context &ctx) override { + void close(Context &ctx) override { Timer t(ctx, "close_file"); UnmapViewOfFile(this->buf); @@ -64,9 +64,9 @@ class MemoryMappedOutputFile : public OutputFile { HANDLE handle; }; -template -std::unique_ptr> -OutputFile::open(Context &ctx, std::string path, i64 filesize, int perm) { +template +std::unique_ptr> +OutputFile::open(Context &ctx, std::string path, i64 filesize, int perm) { Timer t(ctx, "open_file"); if (path.starts_with('/') && !ctx.arg.chroot.empty()) @@ -86,7 +86,7 @@ OutputFile::open(Context &ctx, std::string path, i64 filesize, int perm } } - OutputFile *file; + OutputFile *file; if (is_special) file = new MallocOutputFile(ctx, path, filesize, perm); else @@ -94,20 +94,25 @@ OutputFile::open(Context &ctx, std::string path, i64 filesize, int perm if (ctx.arg.filler != -1) memset(file->buf, ctx.arg.filler, filesize); - return std::unique_ptr>(file); + return std::unique_ptr>(file); } -template -LockingOutputFile::LockingOutputFile(Context &ctx, std::string path, - int perm) - : OutputFile(path, 0, true) { +template +LockingOutputFile::LockingOutputFile(Context &ctx, std::string path, + int perm) + : OutputFile(path, 0, true) { Fatal(ctx) << "LockingOutputFile is not supported on Windows"; } -template -void LockingOutputFile::resize(Context &ctx, i64 filesize) {} +template +void LockingOutputFile::resize(Context &ctx, i64 filesize) {} -template -void LockingOutputFile::close(Context &ctx) {} +template +void LockingOutputFile::close(Context &ctx) {} + +using E = MOLD_TARGET; + +template class OutputFile; +template class LockingOutputFile; } // namespace mold diff --git a/src/passes.cc b/src/passes.cc index 24b2c35984..099dffcaed 100644 --- a/src/passes.cc +++ b/src/passes.cc @@ -1,6 +1,5 @@ #include "mold.h" #include "blake3.h" -#include "../lib/output-file.h" #include #include @@ -3076,8 +3075,8 @@ void write_separate_debug_file(Context &ctx) { Timer t(ctx, "write_separate_debug_file"); // Open an output file early - LockingOutputFile> *file = - new LockingOutputFile>(ctx, ctx.arg.separate_debug_file, 0666); + LockingOutputFile *file = + new LockingOutputFile(ctx, ctx.arg.separate_debug_file, 0666); // We want to write to the debug info file in background so that the // user doesn't have to wait for it to complete. diff --git a/src/relocatable.cc b/src/relocatable.cc index d582c2edc7..639dc6ae87 100644 --- a/src/relocatable.cc +++ b/src/relocatable.cc @@ -169,8 +169,7 @@ void combine_objects(Context &ctx) { compute_section_headers(ctx); i64 filesize = r_set_osec_offsets(ctx); - ctx.output_file = - OutputFile>::open(ctx, ctx.arg.output, filesize, 0666); + ctx.output_file = OutputFile::open(ctx, ctx.arg.output, filesize, 0666); ctx.buf = ctx.output_file->buf; copy_chunks(ctx);