summaryrefslogtreecommitdiffstats
path: root/build/unix/elfhack
diff options
context:
space:
mode:
Diffstat (limited to 'build/unix/elfhack')
-rw-r--r--build/unix/elfhack/relrhack.cpp71
1 files changed, 67 insertions, 4 deletions
diff --git a/build/unix/elfhack/relrhack.cpp b/build/unix/elfhack/relrhack.cpp
index 2d78d783c9..c55103ea70 100644
--- a/build/unix/elfhack/relrhack.cpp
+++ b/build/unix/elfhack/relrhack.cpp
@@ -12,6 +12,7 @@
#include "relrhack.h"
#include <algorithm>
+#include <cstdio>
#include <cstring>
#include <filesystem>
#include <fstream>
@@ -26,6 +27,8 @@
#include <utility>
#include <vector>
+#include "mozilla/ScopeExit.h"
+
namespace fs = std::filesystem;
class CantSwapSections : public std::runtime_error {
@@ -420,10 +423,40 @@ uint16_t get_elf_machine(std::istream& in) {
return ehdr.e_machine;
}
-int run_command(std::vector<const char*>& args) {
+int run_command(std::vector<const char*>& args, bool use_response_file) {
+ std::string at_file;
+ const char** argv = args.data();
+ std::array<const char*, 3> args_with_atfile{};
+ if (use_response_file) {
+ const char* tmpdir = getenv("TMPDIR");
+ if (!tmpdir) {
+ tmpdir = "/tmp";
+ }
+ std::string tmpfile = tmpdir;
+ tmpfile += "/relrhackXXXXXX";
+ int fd = mkstemp(tmpfile.data());
+ if (fd < 0) {
+ std::cerr << "Failed to create temporary file." << std::endl;
+ return 1;
+ }
+ close(fd);
+ std::ofstream f{tmpfile, f.binary};
+ for (auto arg = std::next(args.begin()); arg != args.end(); ++arg) {
+ f << *arg << "\n";
+ }
+ at_file = "@";
+ at_file += tmpfile;
+ args_with_atfile = {args.front(), at_file.c_str(), nullptr};
+ argv = args_with_atfile.data();
+ }
+ auto guard = mozilla::MakeScopeExit([&] {
+ if (!at_file.empty()) {
+ unlink(at_file.c_str() + 1);
+ }
+ });
pid_t child_pid;
if (posix_spawn(&child_pid, args[0], nullptr, nullptr,
- const_cast<char* const*>(args.data()), environ) != 0) {
+ const_cast<char* const*>(argv), environ) != 0) {
throw std::runtime_error("posix_spawn failed");
}
@@ -442,6 +475,9 @@ int main(int argc, char* argv[]) {
std::optional<fs::path> real_linker = std::nullopt;
bool shared = false;
bool is_android = false;
+ bool use_response_file = false;
+ std::vector<char> response_file;
+ std::vector<const char*> response_file_args;
uint16_t elf_machine = EM_NONE;
// Scan argv in order to prepare the following:
// - get the output file. That's the file we may need to adjust.
@@ -458,6 +494,33 @@ int main(int argc, char* argv[]) {
//
// At the same time, we also construct a new list of arguments, with
// --real-linker filtered out. We'll later inject arguments in that list.
+ if (argc == 2 && argv[1] && argv[1][0] == '@') {
+ // When GCC is given a response file, it wraps all arguments into a
+ // new response file with all arguments, even if originally there were
+ // arguments and a response file.
+ // In that case, we can't scan for arguments, so we need to read the
+ // response file. And as we change the arguments, we'll need to write
+ // a new one.
+ std::ifstream f{argv[1] + 1, f.binary | f.ate};
+ if (!f) {
+ std::cerr << "Failed to read " << argv[1] + 1 << std::endl;
+ return 1;
+ }
+ size_t len = f.tellg();
+ response_file = read_vector_at<char>(f, 0, len);
+ std::replace(response_file.begin(), response_file.end(), '\n', '\0');
+ if (len && response_file[len - 1] != '\0') {
+ response_file.push_back('\0');
+ }
+ response_file_args.push_back(argv[0]);
+ for (const char* a = response_file.data();
+ a < response_file.data() + response_file.size(); a += strlen(a) + 1) {
+ response_file_args.push_back(a);
+ }
+ argv = const_cast<char**>(response_file_args.data());
+ argc = response_file_args.size();
+ use_response_file = true;
+ }
for (i = 1, argv++; i < argc && *argv; argv++, i++) {
std::string_view arg{*argv};
if (arg == "-shared") {
@@ -538,7 +601,7 @@ int main(int argc, char* argv[]) {
hacked_args.insert(hacked_args.begin() + crti + 1, inject.c_str());
hacked_args.insert(hacked_args.end() - 1, {"-z", "pack-relative-relocs",
"-init=_relrhack_wrap_init"});
- int status = run_command(hacked_args);
+ int status = run_command(hacked_args, use_response_file);
if (status) {
return status;
}
@@ -563,5 +626,5 @@ int main(int argc, char* argv[]) {
}
}
- return run_command(args);
+ return run_command(args, use_response_file);
}