grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Kernel fixes for Cygwin


From: Christian Franke
Subject: [PATCH] Kernel fixes for Cygwin
Date: Sun, 20 Jul 2008 22:51:52 +0200
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071128 SeaMonkey/1.1.7

This adds Cygwin support to kernel sources. It handles the issues introduced by PE->ELF conversion and adds support for HAVE_ASM_USCORE.

Christian

2007-07-20      Christian Franke  <address@hidden>

        * include/grub/dl.h: Remove .previous, gas supports this only
        for ELF format.

        * include/grub/symbol.h [__CYGWIN__] (#define FUNCTION/VARIABLE):
        Remove .type, gas supports this only for ELF format.

        * kern/dl.c (grub_dl_resolve_symbols): Add check for grub_mod_init
        and grub_mod_fini for symbols without a type. Handle HAVE_ASM_USCORE
        case for these symbols.
        (grub_dl_resolve_dependencies): Add check for trailing nullbytes
        in symbol table. This fixes an infinite loop if table is zero filled.

        * kern/i386/dl.c [__CYGWIN__] (fix_pc_rel_relocation): New function
        to fix bad PC relative relocation produced by objcopy.
        [__CYGWIN__] (grub_arch_dl_relocate_symbols): Add fix of PC relative 
relocation.
        (grub_arch_dl_relocate_symbols): Abort on unknown relocation type.


diff --git a/include/grub/dl.h b/include/grub/dl.h
index b630c6f..3029f95 100644
--- a/include/grub/dl.h
+++ b/include/grub/dl.h
@@ -40,11 +40,12 @@ grub_##name##_fini (void) { grub_mod_fini (); } \
 static void \
 grub_mod_fini (void)
 
+/* Note: .previous not supported for non-ELF targets.  */
 #define GRUB_MOD_NAME(name)    \
-__asm__ (".section .modname,\"S\"\n.string \"" #name "\"\n.previous")
+__asm__ (".section .modname\n.string \"" #name "\"\n")
 
 #define GRUB_MOD_DEP(name)     \
-__asm__ (".section .moddeps,\"S\"\n.string \"" #name "\"\n.previous")
+__asm__ (".section .moddeps\n.string \"" #name "\"\n")
 
 struct grub_dl_segment
 {
diff --git a/include/grub/symbol.h b/include/grub/symbol.h
index aa0ea5a..72209d1 100644
--- a/include/grub/symbol.h
+++ b/include/grub/symbol.h
@@ -28,8 +28,14 @@
 # define EXT_C(sym)    sym
 #endif
 
+#ifndef __CYGWIN__
 #define FUNCTION(x)    .globl EXT_C(x) ; .type EXT_C(x), "function" ; EXT_C(x):
 #define VARIABLE(x)    .globl EXT_C(x) ; .type EXT_C(x), "object" ; EXT_C(x):
+#else
+/* .type not supported for non-ELF targets.  XXX: Check this in configure? */
+#define FUNCTION(x)    .globl EXT_C(x) ; EXT_C(x):
+#define VARIABLE(x)    .globl EXT_C(x) ; EXT_C(x):
+#endif
 
 /* Mark an exported symbol.  */
 #ifndef GRUB_SYMBOL_GENERATOR
diff --git a/kern/dl.c b/kern/dl.c
index c0d9f1d..7950c0d 100644
--- a/kern/dl.c
+++ b/kern/dl.c
@@ -53,6 +53,12 @@ typedef Elf64_Sym Elf_Sym;
 
 #endif
 
+#ifdef HAVE_ASM_USCORE
+# define SYM_USCORE "_"
+#else
+# define SYM_USCORE ""
+#endif
+
 
 
 struct grub_dl_list
@@ -347,17 +353,31 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
       unsigned char type = ELF_ST_TYPE (sym->st_info);
       unsigned char bind = ELF_ST_BIND (sym->st_info);
       const char *name = str + sym->st_name;
-      
+      int check_mod_func = 0;
+
       switch (type)
        {
        case STT_NOTYPE:
-         /* Resolve a global symbol.  */
-         if (sym->st_name != 0 && sym->st_shndx == 0)
+         if (sym->st_name != 0)
            {
-             sym->st_value = (Elf_Addr) grub_dl_resolve_symbol (name);
-             if (! sym->st_value)
-               return grub_error (GRUB_ERR_BAD_MODULE,
-                                  "the symbol `%s' not found", name);
+           if (sym->st_shndx == 0)
+             {
+               /* Resolve a global symbol.  */
+               sym->st_value = (Elf_Addr) grub_dl_resolve_symbol (name);
+               if (! sym->st_value)
+                 return grub_error (GRUB_ERR_BAD_MODULE,
+                                    "the symbol `%s' not found", name);
+             }
+           else
+             { /* Static functions and global variables have no type
+                  if initial format was not ELF.  */
+               sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
+                                                                     
sym->st_shndx);
+               if (bind == STB_LOCAL)
+                 check_mod_func = 1;
+               else if (grub_dl_register_symbol (name, (void *) sym->st_value, 
mod))
+                 return grub_errno;
+             }
            }
          else
            sym->st_value = 0;
@@ -374,14 +394,10 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
        case STT_FUNC:
          sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
                                                                sym->st_shndx);
-         if (bind != STB_LOCAL)
-           if (grub_dl_register_symbol (name, (void *) sym->st_value, mod))
-             return grub_errno;
-         
-         if (grub_strcmp (name, "grub_mod_init") == 0)
-           mod->init = (void (*) (grub_dl_t)) sym->st_value;
-         else if (grub_strcmp (name, "grub_mod_fini") == 0)
-           mod->fini = (void (*) (void)) sym->st_value;
+         if (bind == STB_LOCAL)
+           check_mod_func = 1;
+         else if (grub_dl_register_symbol (name, (void *) sym->st_value, mod))
+           return grub_errno;
          break;
 
        case STT_SECTION:
@@ -397,6 +413,13 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
          return grub_error (GRUB_ERR_BAD_MODULE,
                             "unknown symbol type `%d'", (int) type);
        }
+      if (check_mod_func)
+        {
+         if (grub_strcmp (name, SYM_USCORE "grub_mod_init") == 0)
+           mod->init = (void (*) (grub_dl_t)) sym->st_value;
+         else if (grub_strcmp (name, SYM_USCORE "grub_mod_fini") == 0)
+           mod->fini = (void (*) (void)) sym->st_value;
+        }
     }
 
   return GRUB_ERR_NONE;
@@ -454,7 +477,7 @@ grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e)
        const char *name = (char *) e + s->sh_offset;
        const char *max = name + s->sh_size;
 
-       while (name < max)
+       while (name < max && *name) /* Segment may contain trailing 0.  */
          {
            grub_dl_t m;
            grub_dl_dep_t dep;
diff --git a/kern/i386/dl.c b/kern/i386/dl.c
index e9e43e5..94d1510 100644
--- a/kern/i386/dl.c
+++ b/kern/i386/dl.c
@@ -37,6 +37,28 @@ grub_arch_dl_check_header (void *ehdr)
   return GRUB_ERR_NONE;
 }
 
+#ifdef __CYGWIN__
+/* Fix PC relative relocation.  Objcopy does not adjust
+the addent when converting from pe-i386 to elf32-i386.  */
+static int
+fix_pc_rel_relocation (Elf32_Word *addr)
+{
+  /* To be safe, check instruction first.  */
+  const unsigned char * pc = (const unsigned char *)addr - 1;
+  if (!(*pc == 0xe8/*call*/ || *pc == 0xe9/*jmp*/))
+    return grub_error (GRUB_ERR_BAD_MODULE, "unknown pc-relative instruction 
%02x", *pc);
+  /* Check and adjust offset.  */
+  if (*addr != (Elf32_Word)-4)
+    {
+      if (*addr != 0)
+       return grub_error (GRUB_ERR_BAD_MODULE, "invalid pc-relative relocation 
base %lx",
+                          (long)(*addr));
+      *addr = (Elf32_Word)-4;
+    }
+  return GRUB_ERR_NONE;
+}
+#endif
+
 /* Relocate symbols.  */
 grub_err_t
 grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
@@ -99,9 +121,17 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
                    break;
 
                  case R_386_PC32:
+#ifdef __CYGWIN__
+                   if (fix_pc_rel_relocation (addr))
+                     return grub_errno;
+#endif
                    *addr += (sym->st_value - (Elf32_Word) seg->addr
                              - rel->r_offset);
                    break;
+
+                 default:
+                   return grub_error (GRUB_ERR_BAD_MODULE, "unknown relocation 
type %x.",
+                                      ELF32_R_TYPE (rel->r_info));
                  }
              }
          }

reply via email to

[Prev in Thread] Current Thread [Next in Thread]