]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
elf symbols
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Thu, 14 Jan 2010 18:14:24 +0000 (19:14 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Thu, 14 Jan 2010 18:14:24 +0000 (19:14 +0100)
include/grub/multiboot.h
loader/i386/multiboot_elfxx.c
loader/i386/multiboot_mbi.c

index 1df152056e016d8f0423af65d0962254302d5b79..830490170804c3986d84c015ee761c6cff6bc9e0 100644 (file)
@@ -43,6 +43,9 @@ grub_err_t grub_multiboot_init_mbi (int argc, char *argv[]);
 grub_err_t grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
                                      int argc, char *argv[]);
 void grub_multiboot_set_bootdev (void);
+void
+grub_multiboot_add_elfsyms (grub_size_t num, grub_size_t entsize,
+                           unsigned shndx, void *data);
 
 
 #endif /* ! GRUB_MULTIBOOT_HEADER */
index 155de580166e56b5e108feeed29eb1e3c65c87c5..d996835a5c9d88615718b2ad097bb151606eba14 100644 (file)
@@ -129,6 +129,67 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer)
   if (i == ehdr->e_phnum)
     return grub_error (GRUB_ERR_BAD_OS, "entry point isn't in a segment");
 
+  if (ehdr->e_shnum)
+    {
+      grub_uint8_t *shdr, *shdrptr;
+
+      shdr = grub_malloc (ehdr->e_shnum * ehdr->e_shentsize);
+      if (!shdr)
+       return grub_errno;
+      
+      if (grub_file_seek (file, ehdr->e_shoff) == (grub_off_t) -1)
+       return grub_error (GRUB_ERR_BAD_OS,
+                          "invalid offset to section headers");
+
+      if (grub_file_read (file, shdr, ehdr->e_shnum * ehdr->e_shentsize)
+              != (grub_ssize_t) ehdr->e_shnum * ehdr->e_shentsize)
+       return grub_error (GRUB_ERR_BAD_OS,
+                          "couldn't read sections headers from file");
+      
+      for (shdrptr = shdr, i = 0; i < ehdr->e_shnum;
+          shdrptr += ehdr->e_shentsize, i++)
+       {
+         Elf_Shdr *sh = (Elf_Shdr *) shdrptr;
+         void *src;
+         grub_addr_t target;
+         grub_err_t err;
+
+         /* This section is a loaded section,
+            so we don't care.  */
+         if (sh->sh_addr != 0)
+           continue;
+                     
+         /* This section is empty, so we don't care.  */
+         if (sh->sh_size == 0)
+           continue;
+
+         err 
+           = grub_relocator_alloc_chunk_align (grub_multiboot_relocator,
+                                               &src, &target, 0,
+                                               (0xffffffff - sh->sh_size) + 1,
+                                               sh->sh_size,
+                                               sh->sh_addralign,
+                                               GRUB_RELOCATOR_PREFERENCE_NONE);
+         if (err)
+           {
+             grub_dprintf ("multiboot_loader", "Error loading shdr %d\n", i);
+             return err;
+           }
+
+         if (grub_file_seek (file, sh->sh_offset) == (grub_off_t) -1)
+           return grub_error (GRUB_ERR_BAD_OS,
+                              "invalid offset in section header");
+
+          if (grub_file_read (file, src, sh->sh_size)
+              != (grub_ssize_t) sh->sh_size)
+           return grub_error (GRUB_ERR_BAD_OS,
+                              "couldn't read segment from file");
+         sh->sh_addr = target;
+       }
+      grub_multiboot_add_elfsyms (ehdr->e_shnum, ehdr->e_shentsize,
+                                 ehdr->e_shstrndx, shdr);
+    }
+
 #undef phdr
 
   return grub_errno;
index 675d4c283685a22f9eecdb35edb57bd47ef457db..dbc8dcdfd3674140920da16ed46d51637dabcd87 100644 (file)
@@ -46,6 +46,9 @@ static unsigned modcnt;
 static char *cmdline = NULL;
 static grub_uint32_t bootdev;
 static int bootdev_set;
+static grub_size_t elf_sec_num, elf_sec_entsize;
+static unsigned elf_sec_shstrndx;
+static void *elf_sections;
 
 /* Return the length of the Multiboot mmap that will be needed to allocate
    our platform's map.  */
@@ -73,7 +76,8 @@ grub_multiboot_get_mbi_size (void)
 {
   return sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4)
     + modcnt * sizeof (struct multiboot_mod_list) + total_modcmd
-    + ALIGN_UP (sizeof(PACKAGE_STRING), 4) + grub_get_multiboot_mmap_len ();
+    + ALIGN_UP (sizeof(PACKAGE_STRING), 4) + grub_get_multiboot_mmap_len ()
+    + elf_sec_entsize * elf_sec_num;
 }
 
 /* Fill previously allocated Multiboot mmap.  */
@@ -192,9 +196,30 @@ grub_multiboot_make_mbi (grub_uint32_t *target)
       mbi->flags |= MULTIBOOT_INFO_BOOTDEV;
     }
 
+  if (elf_sec_num)
+    {
+      mbi->u.elf_sec.addr = ptrdest;
+      grub_memcpy (ptrorig, elf_sections, elf_sec_entsize * elf_sec_num);
+      mbi->u.elf_sec.num = elf_sec_num;
+      mbi->u.elf_sec.size = elf_sec_entsize;
+      mbi->u.elf_sec.shndx = elf_sec_shstrndx;
+
+      mbi->flags |= MULTIBOOT_INFO_ELF_SHDR;
+    }
+
   return GRUB_ERR_NONE;
 }
 
+void
+grub_multiboot_add_elfsyms (grub_size_t num, grub_size_t entsize,
+                           unsigned shndx, void *data)
+{
+  elf_sec_num = num;
+  elf_sec_shstrndx = shndx;
+  elf_sec_entsize = entsize;
+  elf_sections = data;
+}
+
 void
 grub_multiboot_free_mbi (void)
 {
@@ -215,6 +240,11 @@ grub_multiboot_free_mbi (void)
     }
   modules = NULL;
   modules_last = NULL;
+
+  grub_free (elf_sections);
+  elf_sections = NULL;
+  elf_sec_entsize = 0;
+  elf_sec_num = 0;
 }
 
 grub_err_t