jdx/mise · error
ELF uses PN_XNUM program header counts
Error message
ELF uses PN_XNUM program header counts
What it means
ELF's extended section numbering (PN_XNUM) stores the real program header count in section header 0 rather than e_phnum, and e_phnum then holds the escape value 0xffff. This parser does not implement PN_XNUM, so any binary reporting e_phnum >= 0xffff is rejected rather than misparsed. Such binaries are extremely rare (they need ~65k program headers).
Solutions
- Confirm the binary is not corrupted (readelf -h shows a sane program header count); re-extract if corrupted.
- For genuine PN_XNUM binaries, fall back to an external tool (patchelf) instead of this parser.
- Skip patching such files and record them as unsupported in the relocation flow.
Defensive patterns
Strategy: type-guard
Validate before calling
let e_phnum = u16::from_le_bytes([content[56], content[57]]);
if e_phnum >= 0xffff { /* PN_XNUM binary: skip or use external patchelf */ } Type guard
fn uses_pn_xnum(elf: &[u8]) -> bool {
elf.len() > 58 && u16::from_le_bytes([elf[56], elf[57]]) == 0xffff
} Try / catch
match read_phdrs(&content) {
Err(e) if e.to_string().contains("PN_XNUM") => {
// route to patchelf or skip with a recorded warning
}
other => other?,
} Prevention
- Reject or route out binaries with extended section numbering before calling the patcher.
- Validate bottle checksums to catch corruption that garbles e_phnum.
- Keep the relocation pipeline best-effort: log and skip unsupported ELF shapes.
When it happens
Trigger: Calling elf::patch or read_linkage on an ELF whose e_phnum field is 0xffff or larger, i.e. a PN_XNUM-encoded binary or a corrupted file with a garbage program-header count.
Common situations: Processing machine-generated or fuzzed binaries; a corrupted bottle; (rarely) a deliberately huge binary built with tens of thousands of segments that uses extended numbering.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- unexpected ELF e_phentsize
- brew-cask: : unsupported archive type for
- brew-cask: : unsupported archive type for
- cannot relocate : rpath must grow but the dynamic string…
- content-level SLSA verification only supports archive…
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/f67404801c6bd1a1.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/packages/brew/elf.rs:117
#[derive(Clone, Copy)]
struct Phdr {
p_type: u32,
p_offset: u64,
p_vaddr: u64,
p_filesz: u64,
p_memsz: u64,
p_align: u64,
}
fn read_phdrs(content: &[u8]) -> Result<Vec<Phdr>> {
let e_phoff = rd_u64(content, 32)? as usize;
let e_phentsize = rd_u16(content, 54)? as usize;
let e_phnum = rd_u16(content, 56)? as usize;
if e_phentsize != PHDR_SIZE {
bail!("unexpected ELF e_phentsize {e_phentsize}");
}
if e_phnum >= 0xffff {
bail!("ELF uses PN_XNUM program header counts");
}
let mut phdrs = Vec::with_capacity(e_phnum);
for i in 0..e_phnum {
let off = e_phoff + i * PHDR_SIZE;
phdrs.push(Phdr {
p_type: rd_u32(content, off)?,
p_offset: rd_u64(content, off + 8)?,
p_vaddr: rd_u64(content, off + 16)?,
p_filesz: rd_u64(content, off + 32)?,
p_memsz: rd_u64(content, off + 40)?,
p_align: rd_u64(content, off + 48)?,
});
}
Ok(phdrs)
}
fn vaddr_to_offset(phdrs: &[Phdr], vaddr: u64) -> Option<usize> {
phdrsView on GitHub (pinned to 533346cc37)