📄 grub-mkimage.c
字号:
/* * GRUB -- GRand Unified Bootloader * Copyright (C) 2004,2005,2006,2007 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRUB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GRUB. If not, see <http://www.gnu.org/licenses/>. */#include <stdio.h>#include <stdint.h>#include <unistd.h>#include <fcntl.h>#include <getopt.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <grub/elf.h>#include <grub/util/misc.h>#include <grub/util/resolve.h>#include <grub/kernel.h>#include <grub/efi/pe32.h>#include <grub/machine/kernel.h>static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB;static inline Elf32_Addralign_address (Elf32_Addr addr, unsigned alignment){ return (addr + alignment - 1) & ~(alignment - 1);}static inline Elf32_Addralign_pe32_section (Elf32_Addr addr){ return align_address (addr, GRUB_PE32_SECTION_ALIGNMENT);}/* Read the whole kernel image. Return the pointer to a read image, and store the size in bytes in *SIZE. */static char *read_kernel_module (const char *dir, char *prefix, size_t *size){ char *kernel_image; char *kernel_path; kernel_path = grub_util_get_path (dir, "kernel.mod"); *size = grub_util_get_image_size (kernel_path); kernel_image = grub_util_read_image (kernel_path); free (kernel_path); if (GRUB_KERNEL_MACHINE_PREFIX + strlen (prefix) + 1 > GRUB_KERNEL_MACHINE_DATA_END) grub_util_error ("prefix too long"); strcpy (kernel_image + 0x34 + GRUB_KERNEL_MACHINE_PREFIX, prefix); return kernel_image;}/* Return if the ELF header is valid. */static intcheck_elf_header (Elf32_Ehdr *e, size_t size){ if (size < sizeof (*e) || e->e_ident[EI_MAG0] != ELFMAG0 || e->e_ident[EI_MAG1] != ELFMAG1 || e->e_ident[EI_MAG2] != ELFMAG2 || e->e_ident[EI_MAG3] != ELFMAG3 || e->e_ident[EI_VERSION] != EV_CURRENT || e->e_version != grub_cpu_to_le32 (EV_CURRENT) || e->e_ident[EI_CLASS] != ELFCLASS32 || e->e_ident[EI_DATA] != ELFDATA2LSB || e->e_machine != grub_cpu_to_le16 (EM_386)) return 0; return 1;}/* Return the starting address right after the header, aligned by the section alignment. Allocate 4 section tables for .text, .data, .reloc, and mods. */static Elf32_Addrget_starting_section_address (void){ return align_pe32_section (sizeof (struct grub_pe32_header) + 4 * sizeof (struct grub_pe32_section_table));}/* Determine if this section is a text section. Return false if this section is not allocated. */static intis_text_section (Elf32_Shdr *s){ return ((s->sh_flags & grub_cpu_to_le32 (SHF_EXECINSTR | SHF_ALLOC)) == grub_cpu_to_le32 (SHF_EXECINSTR | SHF_ALLOC));}/* Determine if this section is a data section. This assumes that BSS is also a data section, since the converter initializes BSS when producing PE32 to avoid a bug in EFI implementations. */static intis_data_section (Elf32_Shdr *s){ return (s->sh_flags & grub_cpu_to_le32 (SHF_ALLOC) && ! (s->sh_flags & grub_cpu_to_le32 (SHF_EXECINSTR)));}/* Locate section addresses by merging code sections and data sections into .text and .data, respectively. Return the array of section addresses. */static Elf32_Addr *locate_sections (Elf32_Shdr *sections, Elf32_Half section_entsize, Elf32_Half num_sections, const char *strtab){ int i; Elf32_Addr current_address; Elf32_Addr *section_addresses; Elf32_Shdr *s; section_addresses = xmalloc (sizeof (*section_addresses) * num_sections); memset (section_addresses, 0, sizeof (*section_addresses) * num_sections); current_address = get_starting_section_address (); /* .text */ for (i = 0, s = sections; i < num_sections; i++, s = (Elf32_Shdr *) ((char *) s + section_entsize)) if (is_text_section (s)) { Elf32_Word align = grub_le_to_cpu32 (s->sh_addralign); const char *name = strtab + grub_le_to_cpu32 (s->sh_name); if (align) current_address = align_address (current_address, align); grub_util_info ("locating the section %s at 0x%x", name, current_address); section_addresses[i] = current_address; current_address += grub_le_to_cpu32 (s->sh_size); } current_address = align_pe32_section (current_address); /* .data */ for (i = 0, s = sections; i < num_sections; i++, s = (Elf32_Shdr *) ((char *) s + section_entsize)) if (is_data_section (s)) { Elf32_Word align = grub_le_to_cpu32 (s->sh_addralign); const char *name = strtab + grub_le_to_cpu32 (s->sh_name); if (align) current_address = align_address (current_address, align); grub_util_info ("locating the section %s at 0x%x", name, current_address); section_addresses[i] = current_address; current_address += grub_le_to_cpu32 (s->sh_size); } return section_addresses;}/* Return the symbol table section, if any. */static Elf32_Shdr *find_symtab_section (Elf32_Shdr *sections, Elf32_Half section_entsize, Elf32_Half num_sections){ int i; Elf32_Shdr *s; for (i = 0, s = sections; i < num_sections; i++, s = (Elf32_Shdr *) ((char *) s + section_entsize)) if (s->sh_type == grub_cpu_to_le32 (SHT_SYMTAB)) return s; return 0;}/* Return the address of the string table. */static const char *find_strtab (Elf32_Ehdr *e, Elf32_Shdr *sections, Elf32_Half section_entsize){ Elf32_Shdr *s; char *strtab; s = (Elf32_Shdr *) ((char *) sections + grub_le_to_cpu16 (e->e_shstrndx) * section_entsize); strtab = (char *) e + grub_le_to_cpu32 (s->sh_offset); return strtab;}/* Relocate symbols; note that this function overwrites the symbol table. Return the address of a start symbol. */static Elf32_Addrrelocate_symbols (Elf32_Ehdr *e, Elf32_Shdr *sections, Elf32_Shdr *symtab_section, Elf32_Addr *section_addresses, Elf32_Half section_entsize, Elf32_Half num_sections){ Elf32_Word symtab_size, sym_size, num_syms; Elf32_Off symtab_offset; Elf32_Addr start_address = 0; Elf32_Sym *sym; Elf32_Word i; Elf32_Shdr *strtab_section; const char *strtab; strtab_section = (Elf32_Shdr *) ((char *) sections + (grub_le_to_cpu32 (symtab_section->sh_link) * section_entsize)); strtab = (char *) e + grub_le_to_cpu32 (strtab_section->sh_offset); symtab_size = grub_le_to_cpu32 (symtab_section->sh_size); sym_size = grub_le_to_cpu32 (symtab_section->sh_entsize); symtab_offset = grub_le_to_cpu32 (symtab_section->sh_offset); num_syms = symtab_size / sym_size; for (i = 0, sym = (Elf32_Sym *) ((char *) e + symtab_offset); i < num_syms; i++, sym = (Elf32_Sym *) ((char *) sym + sym_size)) { Elf32_Section index; const char *name; name = strtab + grub_le_to_cpu32 (sym->st_name); index = grub_le_to_cpu16 (sym->st_shndx); if (index == STN_UNDEF) { if (sym->st_name) grub_util_error ("undefined symbol %s", name); else continue; } else if (index >= num_sections) grub_util_error ("section %d does not exist", index); sym->st_value = (grub_le_to_cpu32 (sym->st_value) + section_addresses[index]); grub_util_info ("locating %s at 0x%x", name, sym->st_value); if (! start_address) if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0) start_address = sym->st_value; } return start_address;}/* Return the address of a symbol at the index I in the section S. */static Elf32_Addrget_symbol_address (Elf32_Ehdr *e, Elf32_Shdr *s, Elf32_Word i){ Elf32_Sym *sym; sym = (Elf32_Sym *) ((char *) e + grub_le_to_cpu32 (s->sh_offset) + i * grub_le_to_cpu32 (s->sh_entsize)); return sym->st_value;}/* Return the address of a modified value. */static Elf32_Addrget_target_address (Elf32_Ehdr *e, Elf32_Shdr *s, Elf32_Addr offset){ return (Elf32_Addr) e + grub_le_to_cpu32 (s->sh_offset) + offset;}/* Deal with relocation information. This function relocates addresses within the virtual address space starting from 0. So only relative addresses can be fully resolved. Absolute addresses must be relocated again by a PE32 relocator when loaded. */static voidrelocate_addresses (Elf32_Ehdr *e, Elf32_Shdr *sections, Elf32_Addr *section_addresses, Elf32_Half section_entsize, Elf32_Half num_sections, const char *strtab){ Elf32_Half i; Elf32_Shdr *s; for (i = 0, s = sections; i < num_sections; i++, s = (Elf32_Shdr *) ((char *) s + section_entsize)) if (s->sh_type == grub_cpu_to_le32 (SHT_REL)) { Elf32_Rel *r; Elf32_Word rtab_size, r_size, num_rs; Elf32_Off rtab_offset; Elf32_Shdr *symtab_section; Elf32_Word target_section_index; Elf32_Addr target_section_addr; Elf32_Shdr *target_section; Elf32_Word j; symtab_section = (Elf32_Shdr *) ((char *) sections + (grub_le_to_cpu32 (s->sh_link) * section_entsize)); target_section_index = grub_le_to_cpu32 (s->sh_info); target_section_addr = section_addresses[target_section_index]; target_section = (Elf32_Shdr *) ((char *) sections + (target_section_index * section_entsize)); grub_util_info ("dealing with the relocation section %s for %s", strtab + grub_le_to_cpu32 (s->sh_name), strtab + grub_le_to_cpu32 (target_section->sh_name)); rtab_size = grub_le_to_cpu32 (s->sh_size); r_size = grub_le_to_cpu32 (s->sh_entsize); rtab_offset = grub_le_to_cpu32 (s->sh_offset); num_rs = rtab_size / r_size; for (j = 0, r = (Elf32_Rel *) ((char *) e + rtab_offset); j < num_rs; j++, r = (Elf32_Rel *) ((char *) r + r_size)) { Elf32_Word info; Elf32_Addr offset; Elf32_Addr sym_addr; Elf32_Addr *target; offset = grub_le_to_cpu32 (r->r_offset); target = (Elf32_Addr *) get_target_address (e, target_section, offset); info = grub_le_to_cpu32 (r->r_info);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -