我正在寻找一些帮助,以帮助您理解parse_elf()
中arch/x86/boot/compressed/misc.c
中解压缩的Linux映像的解析。具体来说,我不了解ELF段正在复制和复制的存储区域。下面是一些带注释的代码,显示了我的(误)理解。
for (i = 0; i < ehdr.e_phnum; i++) { // For each segment...
phdr = &phdrs[i];
switch (phdr->p_type) { // Ignore all segments that
case PT_LOAD: // aren't labeled as loadable
#ifdef CONFIG_RELOCATABLE
dest = output; // Set `dest` to be equal to the base of the kernel
// after decompression and KASLR considerations
// Next, add to `dest` the difference between the physical address
// of the segment and where the kernel was told to be loaded by the
// kernel configuration file. It seems to me that this difference
// is equal to `phdr->p_offset`.
dest += (phdr->p_paddr - LOAD_PHYSICAL_ADDR);
#else
// If we aren't considering relocations then just use the physical
// address of the segment as the destination.
dest = (void *)(phdr->p_paddr);
#endif
// Copy, to the destination determined above, from the beginning
// of the decompressed kernel plus the offset to the segment until
// the end of the segment is reached.
memcpy(dest,
output + phdr->p_offset,
phdr->p_filesz);
break;
default: /* Ignore other PT_* */ break;
}
}
令人困惑的是,在重定位的情况下,memcpy
的第一个和第二个参数似乎是相同的,因此调用parse_elf
毫无意义。也许我误解了LOAD_PHYSICAL_ADDR
或phdr->p_paddr
是什么,或者在将内核解压缩后采取的步骤。
非重定位情况更有意义,因为我们只需要从解压缩的内核复制到“硬编码”地址即可。
一些定义:
LOAD_PHYSICAL_ADDR - compiled base of kernel
p_offset - start of segment in decompressed kernel image
p_paddr - place where we want to put this segment
由于可加载段之外还有其他段,如果p_offset = p_paddr,则内核内存中将有未使用的漏洞。 p_paddr跳过孔,因此始终等于或小于p_offset。这样,我们可以从第一个片段开始,然后向下复制以将片段打包到其预期位置。请注意,第一个片段甚至几个片段可能不会移动。
为了进一步说明这些值的来源,p_offset是该段的文件位置。由于文件是顺序加载到内存中的,因此也是解压缩图像中的偏移量。 p_paddr是由compile + link分配给代码或数据段开头的地址。