Где сегменты копируются в / из parse_elf () в ядре Linux? - PullRequest
1 голос
/ 07 апреля 2020

Мне нужна помощь в разборе распакованного Linux изображения в parse_elf() в arch/x86/boot/compressed/misc.c. В частности, я не понимаю, из каких областей памяти сегменты 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, или шаги, предпринятые после распаковки ядра на месте.

Случай отсутствия перемещения имеет больше смысла, поскольку нам просто нужно скопировать из распакованного ядра по «жестко запрограммированному» адресу.

1 Ответ

1 голос
/ 09 апреля 2020

Некоторые определения:

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 + для начала кода или сегмента данных.

Ref: https://linux.die.net/man/5/elf

...