Make elfload not use hooks. Opt for flags and iterators instead.

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2013-03-02 16:45:57 +01:00
parent 7f8c105f61
commit 73bf57e2c8
9 changed files with 298 additions and 629 deletions

View file

@ -1311,89 +1311,6 @@ grub_bsd_load_aout (grub_file_t file, const char *filename)
bss_size);
}
static int
grub_bsd_elf32_size_hook (grub_elf_t elf __attribute__ ((unused)),
Elf32_Phdr *phdr, void *arg __attribute__ ((unused)))
{
Elf32_Addr paddr;
if (phdr->p_type != PT_LOAD
&& phdr->p_type != PT_DYNAMIC)
return 0;
paddr = phdr->p_paddr & 0xFFFFFFF;
if (paddr < kern_start)
kern_start = paddr;
if (paddr + phdr->p_memsz > kern_end)
kern_end = paddr + phdr->p_memsz;
return 0;
}
static grub_err_t
grub_bsd_elf32_hook (Elf32_Phdr * phdr, grub_addr_t * addr, int *do_load)
{
Elf32_Addr paddr;
if (phdr->p_type != PT_LOAD
&& phdr->p_type != PT_DYNAMIC)
{
*do_load = 0;
return 0;
}
*do_load = 1;
phdr->p_paddr &= 0xFFFFFFF;
paddr = phdr->p_paddr;
*addr = (grub_addr_t) (paddr - kern_start + (grub_uint8_t *) kern_chunk_src);
return GRUB_ERR_NONE;
}
static int
grub_bsd_elf64_size_hook (grub_elf_t elf __attribute__ ((unused)),
Elf64_Phdr *phdr, void *arg __attribute__ ((unused)))
{
Elf64_Addr paddr;
if (phdr->p_type != PT_LOAD
&& phdr->p_type != PT_DYNAMIC)
return 0;
paddr = phdr->p_paddr & 0xfffffff;
if (paddr < kern_start)
kern_start = paddr;
if (paddr + phdr->p_memsz > kern_end)
kern_end = paddr + phdr->p_memsz;
return 0;
}
static grub_err_t
grub_bsd_elf64_hook (Elf64_Phdr * phdr, grub_addr_t * addr, int *do_load)
{
Elf64_Addr paddr;
if (phdr->p_type != PT_LOAD
&& phdr->p_type != PT_DYNAMIC)
{
*do_load = 0;
return 0;
}
*do_load = 1;
paddr = phdr->p_paddr & 0xfffffff;
*addr = (grub_addr_t) (paddr - kern_start + (grub_uint8_t *) kern_chunk_src);
return GRUB_ERR_NONE;
}
static grub_err_t
grub_bsd_load_elf (grub_elf_t elf, const char *filename)
{
@ -1405,12 +1322,29 @@ grub_bsd_load_elf (grub_elf_t elf, const char *filename)
if (grub_elf_is_elf32 (elf))
{
grub_relocator_chunk_t ch;
Elf32_Phdr *phdr;
entry = elf->ehdr.ehdr32.e_entry & 0xFFFFFFF;
err = grub_elf32_phdr_iterate (elf, filename,
grub_bsd_elf32_size_hook, NULL);
if (err)
return err;
FOR_ELF32_PHDRS (elf, phdr)
{
Elf32_Addr paddr;
if (phdr->p_type != PT_LOAD
&& phdr->p_type != PT_DYNAMIC)
continue;
paddr = phdr->p_paddr & 0xFFFFFFF;
if (paddr < kern_start)
kern_start = paddr;
if (paddr + phdr->p_memsz > kern_end)
kern_end = paddr + phdr->p_memsz;
}
if (grub_errno)
return grub_errno;
err = grub_relocator_alloc_chunk_addr (relocator, &ch,
kern_start, kern_end - kern_start);
if (err)
@ -1418,7 +1352,7 @@ grub_bsd_load_elf (grub_elf_t elf, const char *filename)
kern_chunk_src = get_virtual_current_address (ch);
err = grub_elf32_load (elf, filename, grub_bsd_elf32_hook, 0, 0);
err = grub_elf32_load (elf, filename, (grub_uint8_t *) kern_chunk_src - kern_start, GRUB_ELF_LOAD_FLAGS_LOAD_PT_DYNAMIC | GRUB_ELF_LOAD_FLAGS_28BITS, 0, 0);
if (err)
return err;
if (kernel_type != KERNEL_TYPE_OPENBSD)
@ -1428,6 +1362,8 @@ grub_bsd_load_elf (grub_elf_t elf, const char *filename)
}
else if (grub_elf_is_elf64 (elf))
{
Elf64_Phdr *phdr;
is_64bit = 1;
if (! grub_cpuid_has_longmode)
@ -1445,10 +1381,25 @@ grub_bsd_load_elf (grub_elf_t elf, const char *filename)
entry_hi = 0;
}
err = grub_elf64_phdr_iterate (elf, filename,
grub_bsd_elf64_size_hook, NULL);
if (err)
return err;
FOR_ELF64_PHDRS (elf, phdr)
{
Elf64_Addr paddr;
if (phdr->p_type != PT_LOAD
&& phdr->p_type != PT_DYNAMIC)
continue;
paddr = phdr->p_paddr & 0xFFFFFFF;
if (paddr < kern_start)
kern_start = paddr;
if (paddr + phdr->p_memsz > kern_end)
kern_end = paddr + phdr->p_memsz;
}
if (grub_errno)
return grub_errno;
grub_dprintf ("bsd", "kern_start = %lx, kern_end = %lx\n",
(unsigned long) kern_start, (unsigned long) kern_end);
@ -1463,7 +1414,7 @@ grub_bsd_load_elf (grub_elf_t elf, const char *filename)
}
err = grub_elf64_load (elf, filename,
grub_bsd_elf64_hook, 0, 0);
(grub_uint8_t *) kern_chunk_src - kern_start, GRUB_ELF_LOAD_FLAGS_LOAD_PT_DYNAMIC | GRUB_ELF_LOAD_FLAGS_28BITS, 0, 0);
if (err)
return err;
if (kernel_type != KERNEL_TYPE_OPENBSD)

View file

@ -55,30 +55,6 @@ grub_chain_unload (void)
return GRUB_ERR_NONE;
}
static grub_err_t
grub_chain_elf32_hook (Elf32_Phdr * phdr, grub_addr_t * addr, int *do_load)
{
grub_err_t err;
grub_relocator_chunk_t ch;
if (phdr->p_type != PT_LOAD)
{
*do_load = 0;
return 0;
}
*do_load = 1;
err = grub_relocator_alloc_chunk_addr (relocator, &ch,
phdr->p_paddr, phdr->p_memsz);
if (err)
return err;
*addr = (grub_addr_t) get_virtual_current_address (ch);
return GRUB_ERR_NONE;
}
static grub_err_t
grub_cmd_chain (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
@ -86,6 +62,7 @@ grub_cmd_chain (grub_command_t cmd __attribute__ ((unused)),
grub_err_t err;
grub_file_t file;
grub_elf_t elf;
Elf32_Phdr *phdr;
if (argc != 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
@ -118,13 +95,47 @@ grub_cmd_chain (grub_command_t cmd __attribute__ ((unused)),
grub_elf_close (elf);
}
entry = elf->ehdr.ehdr32.e_entry & 0xFFFFFF;
err = grub_elf32_load (elf, argv[0], grub_chain_elf32_hook, 0, 0);
entry = elf->ehdr.ehdr32.e_entry;
FOR_ELF32_PHDRS(elf, phdr)
{
grub_uint8_t *load_addr;
grub_relocator_chunk_t ch;
if (phdr->p_type != PT_LOAD)
continue;
err = grub_relocator_alloc_chunk_addr (relocator, &ch,
phdr->p_paddr, phdr->p_memsz);
if (err)
break;
load_addr = get_virtual_current_address (ch);
if (grub_file_seek (elf->file, phdr->p_offset) == (grub_off_t) -1)
return grub_errno;
if (phdr->p_filesz)
{
grub_ssize_t read;
read = grub_file_read (elf->file, load_addr, phdr->p_filesz);
if (read != (grub_ssize_t) phdr->p_filesz)
{
if (!grub_errno)
grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
argv[0]);
break;
}
}
if (phdr->p_filesz < phdr->p_memsz)
grub_memset ((load_addr + phdr->p_filesz),
0, phdr->p_memsz - phdr->p_filesz);
}
grub_elf_close (elf);
if (err)
return err;
if (grub_errno)
return grub_errno;
grub_loader_set (grub_chain_boot, grub_chain_unload, 0);
return GRUB_ERR_NONE;

View file

@ -144,7 +144,7 @@ grub_linux_load32 (grub_elf_t elf, const char *filename,
/* Linux's entry point incorrectly contains a virtual address. */
entry_addr = elf->ehdr.ehdr32.e_entry;
linux_size = grub_elf32_size (elf, filename, &base, 0);
linux_size = grub_elf32_size (elf, &base, 0);
if (linux_size == 0)
return grub_errno;
target_addr = base;
@ -171,22 +171,7 @@ grub_linux_load32 (grub_elf_t elf, const char *filename,
*extra_mem = playground + extraoff;
/* Now load the segments into the area we claimed. */
auto grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load);
grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load)
{
if (phdr->p_type != PT_LOAD)
{
*do_load = 0;
return 0;
}
*do_load = 1;
/* Linux's program headers incorrectly contain virtual addresses.
* Translate those to physical, and offset to the area we claimed. */
*addr = (grub_addr_t) (phdr->p_paddr - base + playground);
return 0;
}
return grub_elf32_load (elf, filename, offset_phdr, 0, 0);
return grub_elf32_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0);
}
static grub_err_t
@ -200,7 +185,7 @@ grub_linux_load64 (grub_elf_t elf, const char *filename,
/* Linux's entry point incorrectly contains a virtual address. */
entry_addr = elf->ehdr.ehdr64.e_entry;
linux_size = grub_elf64_size (elf, filename, &base, 0);
linux_size = grub_elf64_size (elf, &base, 0);
if (linux_size == 0)
return grub_errno;
target_addr = base;
@ -227,21 +212,7 @@ grub_linux_load64 (grub_elf_t elf, const char *filename,
*extra_mem = playground + extraoff;
/* Now load the segments into the area we claimed. */
auto grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load);
grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load)
{
if (phdr->p_type != PT_LOAD)
{
*do_load = 0;
return 0;
}
*do_load = 1;
/* Linux's program headers incorrectly contain virtual addresses.
* Translate those to physical, and offset to the area we claimed. */
*addr = (grub_addr_t) (phdr->p_paddr - base + playground);
return 0;
}
return grub_elf64_load (elf, filename, offset_phdr, 0, 0);
return grub_elf64_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0);
}
static grub_err_t

View file

@ -179,7 +179,7 @@ grub_linux_load32 (grub_elf_t elf, const char *filename)
grub_uint32_t offset;
Elf32_Addr entry;
linux_size = grub_elf32_size (elf, filename, &base_addr, &align);
linux_size = grub_elf32_size (elf, &base_addr, &align);
if (linux_size == 0)
return grub_errno;
/* Pad it; the kernel scribbles over memory beyond its load address. */
@ -203,20 +203,7 @@ grub_linux_load32 (grub_elf_t elf, const char *filename)
linux_addr = seg_addr;
/* Now load the segments into the area we claimed. */
auto grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load);
grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load)
{
if (phdr->p_type != PT_LOAD)
{
*do_load = 0;
return 0;
}
*do_load = 1;
*addr = (phdr->p_paddr - base_addr) + seg_addr;
return 0;
}
return grub_elf32_load (elf, filename, offset_phdr, 0, 0);
return grub_elf32_load (elf, filename, (void *) (seg_addr - base_addr), GRUB_ELF_LOAD_FLAGS_NONE, 0, 0);
}
static grub_err_t
@ -228,7 +215,7 @@ grub_linux_load64 (grub_elf_t elf, const char *filename)
grub_uint64_t offset;
Elf64_Addr entry;
linux_size = grub_elf64_size (elf, filename, &base_addr, &align);
linux_size = grub_elf64_size (elf, &base_addr, &align);
if (linux_size == 0)
return grub_errno;
/* Pad it; the kernel scribbles over memory beyond its load address. */
@ -250,20 +237,7 @@ grub_linux_load64 (grub_elf_t elf, const char *filename)
linux_addr = seg_addr;
/* Now load the segments into the area we claimed. */
auto grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load);
grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load)
{
if (phdr->p_type != PT_LOAD)
{
*do_load = 0;
return 0;
}
*do_load = 1;
*addr = (phdr->p_paddr - base_addr) + seg_addr;
return 0;
}
return grub_elf64_load (elf, filename, offset_phdr, 0, 0);
return grub_elf64_load (elf, filename, (void *) (grub_addr_t) (seg_addr - base_addr), GRUB_ELF_LOAD_FLAGS_NONE, 0, 0);
}
static grub_err_t

View file

@ -261,7 +261,7 @@ grub_linux_load64 (grub_elf_t elf, const char *filename)
linux_entry = elf->ehdr.ehdr64.e_entry;
linux_addr = 0x40004000;
off = 0x4000;
linux_size = grub_elf64_size (elf, filename, 0, 0);
linux_size = grub_elf64_size (elf, 0, 0);
if (linux_size == 0)
return grub_errno;
@ -286,21 +286,7 @@ grub_linux_load64 (grub_elf_t elf, const char *filename)
base = linux_entry - off;
/* Now load the segments into the area we claimed. */
auto grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load);
grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load)
{
if (phdr->p_type != PT_LOAD)
{
*do_load = 0;
return 0;
}
*do_load = 1;
/* Adjust the program load address to linux_addr. */
*addr = (phdr->p_paddr - base) + (linux_addr - off);
return 0;
}
return grub_elf64_load (elf, filename, offset_phdr, 0, 0);
return grub_elf64_load (elf, filename, (void *) (linux_addr - off - base), GRUB_ELF_LOAD_FLAGS_NONE, 0, 0);
}
static grub_err_t