Skip to content

Commit c03eff0

Browse files
Naman JainGitHub Copilot
andcommitted
loader: Fix ELF relocation logic for Linux v6.17+ startup code layout
After Linux v6.17, the x86_64 kernel startup code moved from .head.text to .init.text. Update the loader to check the lowest program header address for relocation, not just the entry point, to handle both old and new kernels. Co-authored-by: GitHub Copilot <copilot@microsoft.com>
1 parent df8d504 commit c03eff0

File tree

1 file changed

+31
-7
lines changed

1 file changed

+31
-7
lines changed

vm/loader/src/elf.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,37 @@ 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+
// Determine the load offset by checking the lowest physical address in the program headers.
141+
// For kernels with assume_pic=true, if the lowest load address is below start_address,
142+
// we need to relocate the entire kernel upward. This handles both:
143+
//
144+
// 1. Old kernels (Linux < v6.17):
145+
// - Startup code is in .head.text at the beginning of .text
146+
// - Entry point is low, matches physical load address
147+
//
148+
// 2. New kernels (Linux v6.17+):
149+
// - Startup code moved to .init.text (commit: "x86/boot: Move startup code out of __head section", Linux v6.17)
150+
// - Entry point is high, but physical load address (from program headers) is still low
151+
//
152+
// This logic ensures both kernel layouts are relocated correctly if needed, based on the actual load address.
153+
let load_offset = if assume_pic {
154+
let mut lowest_paddr = u64::MAX;
155+
for phdr in phdrs {
156+
if phdr.p_type.get(LE) == elf::PT_LOAD {
157+
let p_paddr = phdr.p_paddr.get(LE);
158+
lowest_paddr = lowest_paddr.min(p_paddr);
159+
}
160+
}
161+
if lowest_paddr < start_address {
162+
// Kernel needs relocation: shift everything up so lowest_paddr aligns with start_address
163+
start_address - lowest_paddr + load_offset
164+
} else {
165+
load_offset
166+
}
139167
} else {
140168
load_offset
141169
};
@@ -155,10 +183,6 @@ where
155183
});
156184
}
157185

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

0 commit comments

Comments
 (0)