1
1
mirror of https://github.com/rui314/mold.git synced 2024-11-09 16:05:58 +03:00
mold/elf/subprocess.cc
2022-10-22 14:40:47 +08:00

123 lines
3.0 KiB
C++

#if !defined(_WIN32) && !defined(__APPLE__)
#include "mold.h"
#include "config.h"
#include <filesystem>
#include <signal.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
namespace mold::elf {
#ifdef MOLD_X86_64
// Exiting from a program with large memory usage is slow --
// it may take a few hundred milliseconds. To hide the latency,
// we fork a child and let it do the actual linking work.
std::function<void()> fork_child() {
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe");
exit(1);
}
pid_t pid = fork();
if (pid == -1) {
perror("fork");
exit(1);
}
if (pid > 0) {
// Parent
close(pipefd[1]);
char buf[1];
if (read(pipefd[0], buf, 1) == 1)
_exit(0);
int status;
waitpid(pid, &status, 0);
if (WIFEXITED(status))
_exit(WEXITSTATUS(status));
if (WIFSIGNALED(status))
raise(WTERMSIG(status));
_exit(1);
}
// Child
close(pipefd[0]);
return [=] {
char buf[] = {1};
[[maybe_unused]] int n = write(pipefd[1], buf, 1);
assert(n == 1);
};
}
#endif
template <typename E>
static std::string find_dso(Context<E> &ctx, std::filesystem::path self) {
// Look for mold-wrapper.so from the same directory as the executable is.
std::filesystem::path path = self.parent_path() / "mold-wrapper.so";
std::error_code ec;
if (std::filesystem::is_regular_file(path, ec) && !ec)
return path;
// If not found, search $(MOLD_LIBDIR)/mold, which is /usr/local/lib/mold
// by default.
path = MOLD_LIBDIR "/mold/mold-wrapper.so";
if (std::filesystem::is_regular_file(path, ec) && !ec)
return path;
// Look for ../lib/mold/mold-wrapper.so
path = self.parent_path() / "../lib/mold/mold-wrapper.so";
if (std::filesystem::is_regular_file(path, ec) && !ec)
return path;
Fatal(ctx) << "mold-wrapper.so is missing";
}
template <typename E>
[[noreturn]]
void process_run_subcommand(Context<E> &ctx, int argc, char **argv) {
assert(argv[1] == "-run"s || argv[1] == "--run"s);
if (!argv[2])
Fatal(ctx) << "-run: argument missing";
// Get the mold-wrapper.so path
std::string self = get_self_path();
std::string dso_path = find_dso(ctx, self);
// Set environment variables
putenv(strdup(("LD_PRELOAD=" + dso_path).c_str()));
putenv(strdup(("MOLD_PATH=" + self).c_str()));
// If ld, ld.lld or ld.gold is specified, run mold itself
if (std::string cmd = filepath(argv[2]).filename();
cmd == "ld" || cmd == "ld.lld" || cmd == "ld.gold") {
std::vector<char *> args;
args.push_back(argv[0]);
args.insert(args.end(), argv + 3, argv + argc);
args.push_back(nullptr);
execv(self.c_str(), args.data());
Fatal(ctx) << "mold -run failed: " << self << ": " << errno_string();
}
// Execute a given command
execvp(argv[2], argv + 2);
Fatal(ctx) << "mold -run failed: " << argv[2] << ": " << errno_string();
}
using E = MOLD_TARGET;
template void process_run_subcommand(Context<E> &, int, char **);
} // namespace mold::elf
#endif