forked from mirrors/gecko-dev
Bug 1892493 - Support reading a response file when that's the only thing on the command line. r=sergesanspaille
Differential Revision: https://phabricator.services.mozilla.com/D208284
This commit is contained in:
parent
4856fd3c1e
commit
e41b7821eb
1 changed files with 67 additions and 4 deletions
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "relrhack.h"
|
#include "relrhack.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
@ -26,6 +27,8 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "mozilla/ScopeExit.h"
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
class CantSwapSections : public std::runtime_error {
|
class CantSwapSections : public std::runtime_error {
|
||||||
|
|
@ -420,10 +423,40 @@ uint16_t get_elf_machine(std::istream& in) {
|
||||||
return ehdr.e_machine;
|
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;
|
pid_t child_pid;
|
||||||
if (posix_spawn(&child_pid, args[0], nullptr, nullptr,
|
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");
|
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;
|
std::optional<fs::path> real_linker = std::nullopt;
|
||||||
bool shared = false;
|
bool shared = false;
|
||||||
bool is_android = 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;
|
uint16_t elf_machine = EM_NONE;
|
||||||
// Scan argv in order to prepare the following:
|
// Scan argv in order to prepare the following:
|
||||||
// - get the output file. That's the file we may need to adjust.
|
// - 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
|
// 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.
|
// --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++) {
|
for (i = 1, argv++; i < argc && *argv; argv++, i++) {
|
||||||
std::string_view arg{*argv};
|
std::string_view arg{*argv};
|
||||||
if (arg == "-shared") {
|
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.begin() + crti + 1, inject.c_str());
|
||||||
hacked_args.insert(hacked_args.end() - 1, {"-z", "pack-relative-relocs",
|
hacked_args.insert(hacked_args.end() - 1, {"-z", "pack-relative-relocs",
|
||||||
"-init=_relrhack_wrap_init"});
|
"-init=_relrhack_wrap_init"});
|
||||||
int status = run_command(hacked_args);
|
int status = run_command(hacked_args, use_response_file);
|
||||||
if (status) {
|
if (status) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
@ -563,5 +626,5 @@ int main(int argc, char* argv[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return run_command(args);
|
return run_command(args, use_response_file);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue