Skip to content

Commit c430e9d

Browse files
namancseGitHub Copilot
andauthored
loader: Fix ELF relocation logic for Linux v6.17+ startup code layout (#2298)
After Linux v6.17, the x86_64 kernel startup code moved from .head.text to .init.text. This moves the startup code to an address, higher than the actual physical load address. Update the loader to check the lowest program header address for relocation, not just the entry point, to handle both old and new kernels. This issue was identified when latest upstream kernel is built with latest openvmm. Compilation error: Error: underhill kernel loader Caused by: 0: kernel load error 1: elf loader error 2: invalid ELF program header memory offset 134217728, below start 136314880 Tested the change, for bootup, both with current mainline and latest upstream kernel. Co-authored-by: Naman Jain <namjain@microsoft.com> Co-authored-by: GitHub Copilot <copilot@microsoft.com>
1 parent 0016dfb commit c430e9d

File tree

1 file changed

+23
-7
lines changed

1 file changed

+23
-7
lines changed

vm/loader/src/elf.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,29 @@ where
133133
}
134134

135135
let e_entry = ehdr.e_entry.get(LE);
136-
let load_offset = if assume_pic && e_entry < start_address {
137-
// The kernel is assumed to contain PIC
138-
start_address + load_offset
136+
let phdrs = ehdr
137+
.program_headers(LE, &reader)
138+
.map_err(Error::InvalidProgramHeader)?;
139+
140+
// For PIC kernels, calculate load offset by checking lowest paddr in program headers.
141+
// If it is below start_address, relocate kernel upward. Handles both:
142+
// - Old kernels (< v6.17): startup code is in .head.text at start of .text, low entry point,
143+
// and matches physical load address
144+
// - New kernels (≥ v6.17): startup code is in .init.text (commit: "x86/boot: Move startup code out of __head section"),
145+
// high entry point but low physical load address
146+
let load_offset = if assume_pic {
147+
let mut lowest_paddr = u64::MAX;
148+
for phdr in phdrs {
149+
if phdr.p_type.get(LE) == elf::PT_LOAD {
150+
let p_paddr = phdr.p_paddr.get(LE);
151+
lowest_paddr = lowest_paddr.min(p_paddr);
152+
}
153+
}
154+
if lowest_paddr < start_address {
155+
start_address - lowest_paddr + load_offset
156+
} else {
157+
load_offset
158+
}
139159
} else {
140160
load_offset
141161
};
@@ -155,10 +175,6 @@ where
155175
});
156176
}
157177

158-
let phdrs = ehdr
159-
.program_headers(LE, &reader)
160-
.map_err(Error::InvalidProgramHeader)?;
161-
162178
// The first pass on the sections provides the layout data
163179
let (lowest_addr, last_offset, reloc_bias) = {
164180
let mut lowest_addr = u64::MAX;

0 commit comments

Comments
 (0)