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  <[EMAIL PROTECTED]>

        * 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));
 		  }
 	      }
 	  }
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to