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:
Mike Hommey 2024-04-29 20:58:36 +00:00
Родитель 4856fd3c1e
Коммит e41b7821eb
1 изменённых файлов: 67 добавлений и 4 удалений

Просмотреть файл

@ -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);
}