grub2/0185-Make-elfload-not-use-hooks.-Opt-for-flags-and-iterat.patch
2013-06-07 14:03:56 -04:00

1184 lines
33 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 6b0582fa0af9c5b2c3537198b3b142222137978c Mon Sep 17 00:00:00 2001
From: Vladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Date: Sat, 2 Mar 2013 16:45:57 +0100
Subject: [PATCH 185/471] Make elfload not use hooks. Opt for flags and
iterators instead.
---
ChangeLog | 4 +
grub-core/kern/elf.c | 455 +++------------------------
grub-core/kern/elfXX.c | 144 +++++++++
grub-core/loader/i386/bsd.c | 137 +++-----
grub-core/loader/i386/coreboot/chainloader.c | 69 ++--
grub-core/loader/mips/linux.c | 37 +--
grub-core/loader/powerpc/ieee1275/linux.c | 34 +-
grub-core/loader/sparc64/ieee1275/linux.c | 18 +-
include/grub/elfload.h | 35 ++-
9 files changed, 301 insertions(+), 632 deletions(-)
create mode 100644 grub-core/kern/elfXX.c
diff --git a/ChangeLog b/ChangeLog
index d55dd8f..7c80ed6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
2013-03-02 Vladimir Serbinenko <phcoder@gmail.com>
+ Make elfload not use hooks. Opt for flags and iterators instead.
+
+2013-03-02 Vladimir Serbinenko <phcoder@gmail.com>
+
* grub-core/lib/ia64/longjmp.S: Fix the name of longjmp function.
* grub-core/lib/ia64/setjmp.S: Fix the name of setjmp function.
diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c
index f52ca21..5f99c43 100644
--- a/grub-core/kern/elf.c
+++ b/grub-core/kern/elf.c
@@ -51,6 +51,7 @@ grub_elf_close (grub_elf_t elf)
grub_file_t file = elf->file;
grub_free (elf->phdrs);
+ grub_free (elf->filename);
grub_free (elf);
if (file)
@@ -85,9 +86,14 @@ grub_elf_file (grub_file_t file, const char *filename)
if (grub_elf_check_header (elf))
goto fail;
+ elf->filename = grub_strdup (filename);
+ if (!elf->filename)
+ goto fail;
+
return elf;
fail:
+ grub_free (elf->filename);
grub_free (elf->phdrs);
grub_free (elf);
return 0;
@@ -112,420 +118,41 @@ grub_elf_open (const char *name)
/* 32-bit */
-
-int
-grub_elf_is_elf32 (grub_elf_t elf)
-{
- return elf->ehdr.ehdr32.e_ident[EI_CLASS] == ELFCLASS32;
-}
-
-static grub_err_t
-grub_elf32_load_phdrs (grub_elf_t elf, const char *filename)
-{
- grub_ssize_t phdrs_size;
-
- phdrs_size = elf->ehdr.ehdr32.e_phnum * elf->ehdr.ehdr32.e_phentsize;
-
- grub_dprintf ("elf", "Loading program headers at 0x%llx, size 0x%lx.\n",
- (unsigned long long) elf->ehdr.ehdr32.e_phoff,
- (unsigned long) phdrs_size);
-
- elf->phdrs = grub_malloc (phdrs_size);
- if (! elf->phdrs)
- return grub_errno;
-
- if ((grub_file_seek (elf->file, elf->ehdr.ehdr32.e_phoff) == (grub_off_t) -1)
- || (grub_file_read (elf->file, elf->phdrs, phdrs_size) != phdrs_size))
- {
- if (!grub_errno)
- grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
- filename);
- return grub_errno;
- }
-
- return GRUB_ERR_NONE;
-}
-
-grub_err_t
-grub_elf32_phdr_iterate (grub_elf_t elf,
- const char *filename,
- grub_elf32_phdr_iterate_hook_t hook, void *hook_arg)
-{
- Elf32_Phdr *phdrs;
- unsigned int i;
-
- if (! elf->phdrs)
- if (grub_elf32_load_phdrs (elf, filename))
- return grub_errno;
- phdrs = elf->phdrs;
-
- for (i = 0; i < elf->ehdr.ehdr32.e_phnum; i++)
- {
- Elf32_Phdr *phdr = phdrs + i;
- grub_dprintf ("elf",
- "Segment %u: type 0x%x paddr 0x%lx memsz 0x%lx "
- "filesz %lx\n",
- i, phdr->p_type,
- (unsigned long) phdr->p_paddr,
- (unsigned long) phdr->p_memsz,
- (unsigned long) phdr->p_filesz);
- if (hook (elf, phdr, hook_arg))
- break;
- }
-
- return grub_errno;
-}
-
-struct grub_elf32_size_ctx
-{
- Elf32_Addr segments_start, segments_end;
- int nr_phdrs;
- grub_uint32_t curr_align;
-};
-
-/* Run through the program headers to calculate the total memory size we
- * should claim. */
-static int
-grub_elf32_calcsize (grub_elf_t _elf __attribute__ ((unused)),
- Elf32_Phdr *phdr, void *data)
-{
- struct grub_elf32_size_ctx *ctx = data;
-
- /* Only consider loadable segments. */
- if (phdr->p_type != PT_LOAD)
- return 0;
- ctx->nr_phdrs++;
- if (phdr->p_paddr < ctx->segments_start)
- ctx->segments_start = phdr->p_paddr;
- if (phdr->p_paddr + phdr->p_memsz > ctx->segments_end)
- ctx->segments_end = phdr->p_paddr + phdr->p_memsz;
- if (ctx->curr_align < phdr->p_align)
- ctx->curr_align = phdr->p_align;
- return 0;
-}
-
-/* Calculate the amount of memory spanned by the segments. */
-grub_size_t
-grub_elf32_size (grub_elf_t elf, const char *filename,
- Elf32_Addr *base, grub_uint32_t *max_align)
-{
- struct grub_elf32_size_ctx ctx = {
- .segments_start = (Elf32_Addr) -1,
- .segments_end = 0,
- .nr_phdrs = 0,
- .curr_align = 1
- };
-
- grub_elf32_phdr_iterate (elf, filename, grub_elf32_calcsize, &ctx);
-
- if (base)
- *base = 0;
-
- if (ctx.nr_phdrs == 0)
- {
- grub_error (GRUB_ERR_BAD_OS, "no program headers present");
- return 0;
- }
-
- if (ctx.segments_end < ctx.segments_start)
- {
- /* Very bad addresses. */
- grub_error (GRUB_ERR_BAD_OS, "bad program header load addresses");
- return 0;
- }
-
- if (base)
- *base = ctx.segments_start;
- if (max_align)
- *max_align = ctx.curr_align;
- return ctx.segments_end - ctx.segments_start;
-}
-
-struct grub_elf32_load_ctx
-{
- const char *filename;
- grub_elf32_load_hook_t load_hook;
- grub_addr_t load_base;
- grub_size_t load_size;
-};
-
-static int
-grub_elf32_load_segment (grub_elf_t elf, Elf32_Phdr *phdr, void *data)
-{
- struct grub_elf32_load_ctx *ctx = data;
- grub_addr_t load_addr;
- int do_load = 1;
-
- load_addr = phdr->p_paddr;
- if (ctx->load_hook && ctx->load_hook (phdr, &load_addr, &do_load))
- return 1;
-
- if (! do_load)
- return 0;
-
- if (load_addr < ctx->load_base)
- ctx->load_base = load_addr;
-
- grub_dprintf ("elf", "Loading segment at 0x%llx, size 0x%llx\n",
- (unsigned long long) load_addr,
- (unsigned long long) phdr->p_memsz);
-
- 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, (void *) load_addr, phdr->p_filesz);
- if (read != (grub_ssize_t) phdr->p_filesz)
- {
- /* XXX How can we free memory from `ctx->load_hook'? */
- if (!grub_errno)
- grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
- ctx->filename);
- return grub_errno;
- }
- }
-
- if (phdr->p_filesz < phdr->p_memsz)
- grub_memset ((void *) (long) (load_addr + phdr->p_filesz),
- 0, phdr->p_memsz - phdr->p_filesz);
-
- ctx->load_size += phdr->p_memsz;
-
- return 0;
-}
-
-/* Load every loadable segment into memory specified by `_load_hook'. */
-grub_err_t
-grub_elf32_load (grub_elf_t elf, const char *filename,
- grub_elf32_load_hook_t load_hook,
- grub_addr_t *base, grub_size_t *size)
-{
- struct grub_elf32_load_ctx ctx = {
- .filename = filename,
- .load_hook = load_hook,
- .load_base = (grub_addr_t) -1ULL,
- .load_size = 0
- };
- grub_err_t err;
-
- err = grub_elf32_phdr_iterate (elf, filename, grub_elf32_load_segment, &ctx);
-
- if (base)
- *base = ctx.load_base;
- if (size)
- *size = ctx.load_size;
-
- return err;
-}
+#define ehdrXX ehdr32
+#define ELFCLASSXX ELFCLASS32
+#define ElfXX_Addr Elf32_Addr
+#define grub_elfXX_size grub_elf32_size
+#define grub_elfXX_load grub_elf32_load
+#define FOR_ELFXX_PHDRS FOR_ELF32_PHDRS
+#define grub_elf_is_elfXX grub_elf_is_elf32
+#define grub_elfXX_load_phdrs grub_elf32_load_phdrs
+#define ElfXX_Phdr Elf32_Phdr
+#define grub_uintXX_t grub_uint32_t
+
+#include "elfXX.c"
+
+#undef ehdrXX
+#undef ELFCLASSXX
+#undef ElfXX_Addr
+#undef grub_elfXX_size
+#undef grub_elfXX_load
+#undef FOR_ELFXX_PHDRS
+#undef grub_elf_is_elfXX
+#undef grub_elfXX_load_phdrs
+#undef ElfXX_Phdr
+#undef grub_uintXX_t
/* 64-bit */
-
-int
-grub_elf_is_elf64 (grub_elf_t elf)
-{
- return elf->ehdr.ehdr64.e_ident[EI_CLASS] == ELFCLASS64;
-}
-
-static grub_err_t
-grub_elf64_load_phdrs (grub_elf_t elf, const char *filename)
-{
- grub_ssize_t phdrs_size;
-
- phdrs_size = elf->ehdr.ehdr64.e_phnum * elf->ehdr.ehdr64.e_phentsize;
-
- grub_dprintf ("elf", "Loading program headers at 0x%llx, size 0x%lx.\n",
- (unsigned long long) elf->ehdr.ehdr64.e_phoff,
- (unsigned long) phdrs_size);
-
- elf->phdrs = grub_malloc (phdrs_size);
- if (! elf->phdrs)
- return grub_errno;
-
- if ((grub_file_seek (elf->file, elf->ehdr.ehdr64.e_phoff) == (grub_off_t) -1)
- || (grub_file_read (elf->file, elf->phdrs, phdrs_size) != phdrs_size))
- {
- if (!grub_errno)
- grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
- filename);
- return grub_errno;
- }
-
- return GRUB_ERR_NONE;
-}
-
-grub_err_t
-grub_elf64_phdr_iterate (grub_elf_t elf,
- const char *filename,
- grub_elf64_phdr_iterate_hook_t hook, void *hook_arg)
-{
- Elf64_Phdr *phdrs;
- unsigned int i;
-
- if (! elf->phdrs)
- if (grub_elf64_load_phdrs (elf, filename))
- return grub_errno;
- phdrs = elf->phdrs;
-
- for (i = 0; i < elf->ehdr.ehdr64.e_phnum; i++)
- {
- Elf64_Phdr *phdr = phdrs + i;
- grub_dprintf ("elf",
- "Segment %u: type 0x%x paddr 0x%lx memsz 0x%lx "
- "filesz %lx\n",
- i, phdr->p_type,
- (unsigned long) phdr->p_paddr,
- (unsigned long) phdr->p_memsz,
- (unsigned long) phdr->p_filesz);
- if (hook (elf, phdr, hook_arg))
- break;
- }
-
- return grub_errno;
-}
-
-struct grub_elf64_size_ctx
-{
- Elf64_Addr segments_start, segments_end;
- int nr_phdrs;
- grub_uint64_t curr_align;
-};
-
-/* Run through the program headers to calculate the total memory size we
- * should claim. */
-static int
-grub_elf64_calcsize (grub_elf_t _elf __attribute__ ((unused)),
- Elf64_Phdr *phdr, void *data)
-{
- struct grub_elf64_size_ctx *ctx = data;
-
- /* Only consider loadable segments. */
- if (phdr->p_type != PT_LOAD)
- return 0;
- ctx->nr_phdrs++;
- if (phdr->p_paddr < ctx->segments_start)
- ctx->segments_start = phdr->p_paddr;
- if (phdr->p_paddr + phdr->p_memsz > ctx->segments_end)
- ctx->segments_end = phdr->p_paddr + phdr->p_memsz;
- if (ctx->curr_align < phdr->p_align)
- ctx->curr_align = phdr->p_align;
- return 0;
-}
-
-/* Calculate the amount of memory spanned by the segments. */
-grub_size_t
-grub_elf64_size (grub_elf_t elf, const char *filename,
- Elf64_Addr *base, grub_uint64_t *max_align)
-{
- struct grub_elf64_size_ctx ctx = {
- .segments_start = (Elf64_Addr) -1,
- .segments_end = 0,
- .nr_phdrs = 0,
- .curr_align = 1
- };
-
- grub_elf64_phdr_iterate (elf, filename, grub_elf64_calcsize, &ctx);
-
- if (base)
- *base = 0;
-
- if (ctx.nr_phdrs == 0)
- {
- grub_error (GRUB_ERR_BAD_OS, "no program headers present");
- return 0;
- }
-
- if (ctx.segments_end < ctx.segments_start)
- {
- /* Very bad addresses. */
- grub_error (GRUB_ERR_BAD_OS, "bad program header load addresses");
- return 0;
- }
-
- if (base)
- *base = ctx.segments_start;
- if (max_align)
- *max_align = ctx.curr_align;
- return ctx.segments_end - ctx.segments_start;
-}
-
-struct grub_elf64_load_ctx
-{
- const char *filename;
- grub_elf64_load_hook_t load_hook;
- grub_addr_t load_base;
- grub_size_t load_size;
-};
-
-static int
-grub_elf64_load_segment (grub_elf_t elf, Elf64_Phdr *phdr, void *data)
-{
- struct grub_elf64_load_ctx *ctx = data;
- grub_addr_t load_addr;
- int do_load = 1;
-
- load_addr = phdr->p_paddr;
- if (ctx->load_hook && ctx->load_hook (phdr, &load_addr, &do_load))
- return 1;
-
- if (! do_load)
- return 0;
-
- if (load_addr < ctx->load_base)
- ctx->load_base = load_addr;
-
- grub_dprintf ("elf", "Loading segment at 0x%llx, size 0x%llx\n",
- (unsigned long long) load_addr,
- (unsigned long long) phdr->p_memsz);
-
- 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, (void *) load_addr, phdr->p_filesz);
- if (read != (grub_ssize_t) phdr->p_filesz)
- {
- /* XXX How can we free memory from `ctx->load_hook'? */
- if (!grub_errno)
- grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
- ctx->filename);
- return grub_errno;
- }
- }
-
- if (phdr->p_filesz < phdr->p_memsz)
- grub_memset ((void *) (long) (load_addr + phdr->p_filesz),
- 0, phdr->p_memsz - phdr->p_filesz);
-
- ctx->load_size += phdr->p_memsz;
-
- return 0;
-}
-
-/* Load every loadable segment into memory specified by `_load_hook'. */
-grub_err_t
-grub_elf64_load (grub_elf_t elf, const char *filename,
- grub_elf64_load_hook_t load_hook,
- grub_addr_t *base, grub_size_t *size)
-{
- struct grub_elf64_load_ctx ctx = {
- .filename = filename,
- .load_hook = load_hook,
- .load_base = (grub_addr_t) -1ULL,
- .load_size = 0
- };
- grub_err_t err;
-
- err = grub_elf64_phdr_iterate (elf, filename, grub_elf64_load_segment, &ctx);
-
- if (base)
- *base = ctx.load_base;
- if (size)
- *size = ctx.load_size;
-
- return err;
-}
+#define ehdrXX ehdr64
+#define ELFCLASSXX ELFCLASS64
+#define ElfXX_Addr Elf64_Addr
+#define grub_elfXX_size grub_elf64_size
+#define grub_elfXX_load grub_elf64_load
+#define FOR_ELFXX_PHDRS FOR_ELF64_PHDRS
+#define grub_elf_is_elfXX grub_elf_is_elf64
+#define grub_elfXX_load_phdrs grub_elf64_load_phdrs
+#define ElfXX_Phdr Elf64_Phdr
+#define grub_uintXX_t grub_uint64_t
+
+#include "elfXX.c"
diff --git a/grub-core/kern/elfXX.c b/grub-core/kern/elfXX.c
new file mode 100644
index 0000000..b35e235
--- /dev/null
+++ b/grub-core/kern/elfXX.c
@@ -0,0 +1,144 @@
+int
+grub_elf_is_elfXX (grub_elf_t elf)
+{
+ return elf->ehdr.ehdrXX.e_ident[EI_CLASS] == ELFCLASSXX;
+}
+
+grub_err_t
+grub_elfXX_load_phdrs (grub_elf_t elf)
+{
+ grub_ssize_t phdrs_size;
+
+ if (elf->phdrs)
+ return GRUB_ERR_NONE;
+
+ phdrs_size = elf->ehdr.ehdrXX.e_phnum * elf->ehdr.ehdrXX.e_phentsize;
+
+ grub_dprintf ("elf", "Loading program headers at 0x%llx, size 0x%lx.\n",
+ (unsigned long long) elf->ehdr.ehdrXX.e_phoff,
+ (unsigned long) phdrs_size);
+
+ elf->phdrs = grub_malloc (phdrs_size);
+ if (! elf->phdrs)
+ return grub_errno;
+
+ if ((grub_file_seek (elf->file, elf->ehdr.ehdrXX.e_phoff) == (grub_off_t) -1)
+ || (grub_file_read (elf->file, elf->phdrs, phdrs_size) != phdrs_size))
+ {
+ if (!grub_errno)
+ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
+ elf->filename);
+ return grub_errno;
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+/* Calculate the amount of memory spanned by the segments. */
+grub_size_t
+grub_elfXX_size (grub_elf_t elf,
+ ElfXX_Addr *base, grub_uintXX_t *max_align)
+{
+ ElfXX_Addr segments_start = (ElfXX_Addr) -1;
+ ElfXX_Addr segments_end = 0;
+ int nr_phdrs = 0;
+ grub_uint32_t curr_align = 1;
+ ElfXX_Phdr *phdr;
+
+ /* Run through the program headers to calculate the total memory size we
+ * should claim. */
+ FOR_ELFXX_PHDRS (elf, phdr)
+ {
+ /* Only consider loadable segments. */
+ if (phdr->p_type != PT_LOAD)
+ continue;
+ nr_phdrs++;
+ if (phdr->p_paddr < segments_start)
+ segments_start = phdr->p_paddr;
+ if (phdr->p_paddr + phdr->p_memsz > segments_end)
+ segments_end = phdr->p_paddr + phdr->p_memsz;
+ if (curr_align < phdr->p_align)
+ curr_align = phdr->p_align;
+ }
+
+ if (base)
+ *base = 0;
+
+ if (nr_phdrs == 0)
+ {
+ grub_error (GRUB_ERR_BAD_OS, "no program headers present");
+ return 0;
+ }
+
+ if (segments_end < segments_start)
+ {
+ /* Very bad addresses. */
+ grub_error (GRUB_ERR_BAD_OS, "bad program header load addresses");
+ return 0;
+ }
+
+ if (base)
+ *base = segments_start;
+ if (max_align)
+ *max_align = curr_align;
+ return segments_end - segments_start;
+}
+
+grub_err_t
+grub_elfXX_load (grub_elf_t elf, const char *filename,
+ void *load_offset, enum grub_elf_load_flags load_flags,
+ grub_addr_t *base, grub_size_t *size)
+{
+ grub_addr_t load_base = (grub_addr_t) -1ULL;
+ grub_size_t load_size = 0;
+ ElfXX_Phdr *phdr;
+
+ FOR_ELFXX_PHDRS(elf, phdr)
+ {
+ grub_addr_t load_addr;
+
+ if (phdr->p_type != PT_LOAD && !((load_flags & GRUB_ELF_LOAD_FLAGS_LOAD_PT_DYNAMIC) && phdr->p_type == PT_DYNAMIC))
+ continue;
+
+ load_addr = (grub_addr_t) phdr->p_paddr;
+ if (load_flags & GRUB_ELF_LOAD_FLAGS_28BITS)
+ load_addr &= 0xFFFFFFF;
+ load_addr += (grub_addr_t) load_offset;
+
+ if (load_addr < load_base)
+ load_base = load_addr;
+
+ grub_dprintf ("elf", "Loading segment at 0x%llx, size 0x%llx\n",
+ (unsigned long long) load_addr,
+ (unsigned long long) phdr->p_memsz);
+
+ 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, (void *) 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"),
+ filename);
+ return grub_errno;
+ }
+ }
+
+ if (phdr->p_filesz < phdr->p_memsz)
+ grub_memset ((void *) (long) (load_addr + phdr->p_filesz),
+ 0, phdr->p_memsz - phdr->p_filesz);
+
+ load_size += phdr->p_memsz;
+ }
+
+ if (base)
+ *base = load_base;
+ if (size)
+ *size = load_size;
+
+ return grub_errno;
+}
diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c
index 9b86158..6199609 100644
--- a/grub-core/loader/i386/bsd.c
+++ b/grub-core/loader/i386/bsd.c
@@ -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)
diff --git a/grub-core/loader/i386/coreboot/chainloader.c b/grub-core/loader/i386/coreboot/chainloader.c
index df4e276..505aa0b 100644
--- a/grub-core/loader/i386/coreboot/chainloader.c
+++ b/grub-core/loader/i386/coreboot/chainloader.c
@@ -56,36 +56,13 @@ grub_chain_unload (void)
}
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[])
{
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;
diff --git a/grub-core/loader/mips/linux.c b/grub-core/loader/mips/linux.c
index f2cf7cc..653f8a2 100644
--- a/grub-core/loader/mips/linux.c
+++ b/grub-core/loader/mips/linux.c
@@ -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
diff --git a/grub-core/loader/powerpc/ieee1275/linux.c b/grub-core/loader/powerpc/ieee1275/linux.c
index c977941..9055399 100644
--- a/grub-core/loader/powerpc/ieee1275/linux.c
+++ b/grub-core/loader/powerpc/ieee1275/linux.c
@@ -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
diff --git a/grub-core/loader/sparc64/ieee1275/linux.c b/grub-core/loader/sparc64/ieee1275/linux.c
index c85fcfd..d203377 100644
--- a/grub-core/loader/sparc64/ieee1275/linux.c
+++ b/grub-core/loader/sparc64/ieee1275/linux.c
@@ -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
diff --git a/include/grub/elfload.h b/include/grub/elfload.h
index d1a8d54..f854d0b 100644
--- a/include/grub/elfload.h
+++ b/include/grub/elfload.h
@@ -33,14 +33,10 @@ struct grub_elf_file
Elf32_Ehdr ehdr32;
} ehdr;
void *phdrs;
+ char *filename;
};
typedef struct grub_elf_file *grub_elf_t;
-typedef grub_err_t (*grub_elf32_load_hook_t)
- (Elf32_Phdr *phdr, grub_addr_t *addr, int *load);
-typedef grub_err_t (*grub_elf64_load_hook_t)
- (Elf64_Phdr *phdr, grub_addr_t *addr, int *load);
-
typedef int (*grub_elf32_phdr_iterate_hook_t)
(grub_elf_t elf, Elf32_Phdr *phdr, void *arg);
typedef int (*grub_elf64_phdr_iterate_hook_t)
@@ -52,26 +48,31 @@ grub_err_t grub_elf_close (grub_elf_t);
int grub_elf_is_elf32 (grub_elf_t);
grub_size_t grub_elf32_size (grub_elf_t,
- const char *filename,
Elf32_Addr *, grub_uint32_t *);
+enum grub_elf_load_flags
+ {
+ GRUB_ELF_LOAD_FLAGS_NONE = 0,
+ GRUB_ELF_LOAD_FLAGS_LOAD_PT_DYNAMIC = 1,
+ GRUB_ELF_LOAD_FLAGS_28BITS = 2,
+ };
grub_err_t grub_elf32_load (grub_elf_t, const char *filename,
- grub_elf32_load_hook_t, grub_addr_t *,
+ void *load_offset, enum grub_elf_load_flags flags, grub_addr_t *,
grub_size_t *);
int grub_elf_is_elf64 (grub_elf_t);
grub_size_t grub_elf64_size (grub_elf_t,
- const char *filename,
Elf64_Addr *, grub_uint64_t *);
grub_err_t grub_elf64_load (grub_elf_t, const char *filename,
- grub_elf64_load_hook_t, grub_addr_t *,
+ void *load_offset, enum grub_elf_load_flags flags, grub_addr_t *,
grub_size_t *);
-grub_err_t
-grub_elf32_phdr_iterate (grub_elf_t elf,
- const char *filename,
- grub_elf32_phdr_iterate_hook_t hook, void *hook_arg);
-grub_err_t
-grub_elf64_phdr_iterate (grub_elf_t elf,
- const char *filename,
- grub_elf64_phdr_iterate_hook_t hook, void *hook_arg);
+grub_err_t grub_elf32_load_phdrs (grub_elf_t elf);
+grub_err_t grub_elf64_load_phdrs (grub_elf_t elf);
+
+#define FOR_ELF32_PHDRS(elf, phdr) \
+ for (grub_elf32_load_phdrs (elf), phdr = elf->phdrs; \
+ phdr && phdr < (Elf32_Phdr *) elf->phdrs + elf->ehdr.ehdr32.e_phnum; phdr++)
+#define FOR_ELF64_PHDRS(elf, phdr) \
+ for (grub_elf64_load_phdrs (elf), phdr = elf->phdrs; \
+ phdr && phdr < (Elf64_Phdr *) elf->phdrs + elf->ehdr.ehdr64.e_phnum; phdr++)
#endif /* ! GRUB_ELFLOAD_HEADER */
--
1.8.2.1