Skip to content

Commit df7607a

Browse files
committed
refactor: loader paths from data everywhere — no ld-linux-x86-64 hardcodes
fixup_gcc_specs detects the baked loader name from the specs content and replaces it with resolve_loader()'s answer (any glibc arch); the specs dir is discovered instead of assuming x86_64-linux-gnu. mcpp pack derives the BundleProject PT_INTERP distro path from the loader soname ldd resolved for the binary being packed (LSB /lib64 vs /lib), instead of a hardcoded x86_64 string. The only remaining literal loader names live in linkmodel.cppm's per-arch triple map.
1 parent 6e4c755 commit df7607a

2 files changed

Lines changed: 46 additions & 28 deletions

File tree

src/pack/pack.cppm

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -638,15 +638,23 @@ run(const Plan& plan, const mcpp::config::GlobalConfig& cfg)
638638
return std::unexpected(Error{r.error()});
639639

640640
// PT_INTERP handling differs by mode:
641-
// BundleProject → repoint to /lib64/ld-linux-x86-64.so.2
642-
// (LSB-mandated symlink on glibc distros)
641+
// BundleProject → repoint to the target distro's loader
642+
// (LSB layout: /lib64/<loader> on x86_64,
643+
// /lib/<loader> elsewhere), derived from the
644+
// loader soname ldd resolved for THIS binary —
645+
// arch-correct without hardcoding a name.
643646
// BundleAll → leave PT_INTERP alone; the wrapper script
644647
// ignores it and launches via the bundled
645648
// loader directly.
646649
if (plan.opts.mode == Mode::BundleProject || plan.opts.mode == Mode::None) {
647-
if (auto r = set_interpreter(bundledBinary,
648-
"/lib64/ld-linux-x86-64.so.2", patchelf); !r)
649-
return std::unexpected(Error{r.error()});
650+
if (auto soname = find_loader_soname(*deps); !soname.empty()) {
651+
auto distroLoader =
652+
(soname == "ld-linux-x86-64.so.2" ? "/lib64/" : "/lib/")
653+
+ soname;
654+
if (auto r = set_interpreter(bundledBinary, distroLoader,
655+
patchelf); !r)
656+
return std::unexpected(Error{r.error()});
657+
}
650658
}
651659
}
652660

src/toolchain/post_install.cppm

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -84,41 +84,52 @@ export void patchelf_walk(const std::filesystem::path& dir,
8484
// xlings' home, not mcpp's sandbox glibc — binaries would fail to exec.
8585
//
8686
// Mcpp does a post-install spec rewrite:
87-
// - Dynamically detects the baked-in lib dir from the specs file
88-
// - Replaces the dynamic-linker path with <glibc_lib64>/ld-linux-x86-64.so.2
89-
// - Replaces the rpath with <glibc_lib64>:<gcc_lib64>
87+
// - Dynamically detects the baked-in loader path from the specs file
88+
// - Replaces it with the sandbox glibc payload's loader
89+
// - Replaces the rpath with <glibc_lib>:<gcc_lib64>
9090
// Idempotent — skips if already pointing at the correct glibc.
91-
// Extract the baked-in lib directory from a gcc specs file by finding
92-
// the dynamic-linker path that ends with `/ld-linux-x86-64.so.2`.
93-
// xim bakes the installing user's XLINGS_HOME into specs at install
94-
// time, so the path varies per machinewe cannot hardcode it.
95-
std::string detect_baked_lib_dir(const std::string& specsContent) {
96-
constexpr std::string_view kLoader = "/ld-linux-x86-64.so.2";
97-
auto pos = specsContent.find(kLoader);
91+
// Extract the baked-in glibc loader path (".../ld-linux-<arch>.so.N") from a
92+
// gcc specs file. xim bakes the installing user's XLINGS_HOME into specs at
93+
// install time, so the DIR varies per machine, and the loader NAME varies
94+
// per archdetect both instead of hardcoding either.
95+
std::string detect_baked_loader(const std::string& specsContent) {
96+
constexpr std::string_view kLoaderMark = "/ld-linux-";
97+
auto pos = specsContent.find(kLoaderMark);
9898
if (pos == std::string::npos) return "";
99-
// Walk backwards to find start of the absolute path
99+
// Walk backwards to find start of the absolute path
100100
auto start = pos;
101101
while (start > 0 && specsContent[start - 1] != ' '
102102
&& specsContent[start - 1] != ':'
103103
&& specsContent[start - 1] != ';'
104104
&& specsContent[start - 1] != '\n') {
105105
--start;
106106
}
107-
auto dir = specsContent.substr(start, pos - start);
108-
// Sanity: must be absolute
109-
if (dir.empty() || dir[0] != '/') return "";
110-
// Skip if it already points to the target glibc (no fixup needed)
111-
return dir;
107+
// …and forwards to its end.
108+
auto end = pos + kLoaderMark.size();
109+
while (end < specsContent.size()
110+
&& !std::isspace(static_cast<unsigned char>(specsContent[end]))
111+
&& specsContent[end] != ':' && specsContent[end] != ';') {
112+
++end;
113+
}
114+
auto loader = specsContent.substr(start, end - start);
115+
if (loader.empty() || loader[0] != '/') return "";
116+
return loader;
112117
}
113118

114119
void fixup_gcc_specs(const std::filesystem::path& gccPkgRoot,
115120
const std::filesystem::path& glibcLibDir,
116121
const std::filesystem::path& gccLibDir)
117122
{
118-
auto specsParent = gccPkgRoot / "lib" / "gcc" / "x86_64-linux-gnu";
119-
if (!std::filesystem::exists(specsParent)) return;
123+
std::filesystem::path specsParent;
124+
std::error_code ec;
125+
for (auto it = std::filesystem::directory_iterator(gccPkgRoot / "lib" / "gcc", ec);
126+
!ec && it != std::filesystem::directory_iterator{}; it.increment(ec)) {
127+
if (it->is_directory(ec)) { specsParent = it->path(); break; }
128+
}
129+
if (specsParent.empty()) return;
120130

121-
auto loaderReplacement = (glibcLibDir / "ld-linux-x86-64.so.2").string();
131+
auto loaderReplacement = resolve_loader(glibcLibDir, /*targetTriple=*/{}).string();
132+
if (loaderReplacement.empty()) return;
122133
auto rpathReplacement = std::format("{}:{}",
123134
glibcLibDir.string(),
124135
gccLibDir.string());
@@ -141,13 +152,12 @@ void fixup_gcc_specs(const std::filesystem::path& gccPkgRoot,
141152
std::stringstream ss; ss << is.rdbuf();
142153
std::string content = ss.str();
143154

144-
auto bakedDir = detect_baked_lib_dir(content);
145-
if (bakedDir.empty()) continue;
155+
auto bakedLoader = detect_baked_loader(content);
156+
if (bakedLoader.empty()) continue;
157+
auto bakedDir = std::filesystem::path(bakedLoader).parent_path().string();
146158
// Already pointing at the right place — no fixup needed.
147159
if (bakedDir == glibcLibDir.string()) continue;
148160

149-
auto bakedLoader = bakedDir + "/ld-linux-x86-64.so.2";
150-
151161
// Order matters: replace the full loader file path first so the
152162
// shorter dir pattern doesn't eat its prefix.
153163
replace_all(content, bakedLoader, loaderReplacement);

0 commit comments

Comments
 (0)