This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[LTO] PATCH: Read integral initializers


This patch gives the LTO front end the ability to read initializers
for integer variables.  So, for example:

  int i = 3;

can now be round-tripped through the LTO front end.  

The data is pulled out of the object file.  I have not yet implemented
support for relocations, so if there are any, they will be ignored.

Committed to the LTO branch.

--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

2007-06-28  Mark Mitchell  <mark@codesourcery.com>

	* lto.h (lto_file_vtable): Add read_var_init.
	* lto.c (lto_read_variable_formal_parameter_constant_DIE): Read
	initializers.
	(lto_main): Remove bogus asserts.
	* lto-elf.c (tm.h): Include it.
	(libiberty.y): Likewise.
	(lto_elf_file): Add strtab and symtab.  Rename
	string_table_section_index to sec_strtab.
	(lto_elf_file_vtable): Add lto_elf_read_var_init.
	(lto_elf_get_shdr): New function.
	(lto_elf_free_shdr): Likewise.
	(lto_elf_find_section_data): Use them.
	(lto_elf_read_symtab): New function.
	(lto_elf_lookup_sym): Likewise.
	(lto_elf_free_sym): Likewise.
	(lto_elf_file_open): Tidy.  Call lto_elf_read_symtab.
	(lto_elf_built_init): New function.
	(lto_elf_read_var_init): Likewise.
	* Make-lang.in (lto/lto-elf.o): Depend on $(TM_H).

Index: lto.c
===================================================================
--- lto.c	(revision 126102)
+++ lto.c	(working copy)
@@ -2019,6 +2019,12 @@ lto_read_variable_formal_parameter_const
        use the same method for variables outside of function scopes,
        for consistency.  */
     sorry ("cannot determine storage duration of local variables");
+  /* If there is an initializer, read it now.  */
+  if (!declaration)
+    {
+      lto_file *file = fd->base.file;
+      file->vtable->read_var_init (file, decl);
+    }
   /* If this variable has already been declared, merge the
      declarations.  */
   decl = lto_symtab_merge_var (decl);
@@ -3257,10 +3263,6 @@ lto_main (int debug_p ATTRIBUTE_UNUSED)
       file = lto_elf_file_open (in_fnames[i]);
       if (!file)
 	break;
-#if 0
-      gcc_assert (file->debug_info.base.start);
-      gcc_assert (file->debug_abbrev.base.start);
-#endif
       if (!lto_file_read (file))
 	break;
       lto_elf_file_close (file);
Index: Make-lang.in
===================================================================
--- Make-lang.in	(revision 126102)
+++ Make-lang.in	(working copy)
@@ -82,7 +82,7 @@ lto/lto-lang.o: lto/lto-lang.c $(CONFIG_
 lto/lto.o: lto/lto.c $(CONFIG_H) $(CGRAPH_H) coretypes.h dwarf2.h \
 	$(GGC_H) opts.h $(SYSTEM_H) toplev.h $(TM_H) $(LTO_H)
 lto/lto-elf.o: lto/lto-elf.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
-	toplev.h $(LTO_H) $(LTO_TAGS_H)
+	toplev.h $(LTO_H) $(LTO_TAGS_H) $(TM_H)
 lto/lto-symtab.o: lto/lto-symtab.c $(CONFIG_H) coretypes.h \
 	$(SYSTEM_H) toplev.h $(TREE_H) $(LTO_H) lto/lto-tree.h
 lto/lto-read.o: lto/lto-read.c $(CONFIG_H) $(SYSTEM_H) \
Index: lto-elf.c
===================================================================
--- lto-elf.c	(revision 126102)
+++ lto-elf.c	(working copy)
@@ -34,6 +34,8 @@ Boston, MA 02110-1301, USA.  */
 # endif
 #endif
 #include "lto-tags.h"
+#include "tm.h"
+#include "libiberty.h"
 
 /* An ELF input file.  */
 struct lto_elf_file 
@@ -46,8 +48,12 @@ struct lto_elf_file 
   Elf *elf;
   /* 32 or 64 bits? */
   size_t bits;
-  /* Offset of string table used for section names.  */
-  size_t string_table_section_index;
+  /* Section number of section table.  */
+  size_t strtab;
+  /* Section number of string table used for section names.  */
+  size_t sec_strtab;
+  /* The ELF symbol table.  */
+  Elf_Data *symtab;
 };
 typedef struct lto_elf_file lto_elf_file;
 
@@ -59,12 +65,70 @@ lto_elf_map_fn_body (lto_file *file, con
 static void
 lto_elf_unmap_fn_body (lto_file *file, const char *fn, const void *data);
 
+static void
+lto_elf_read_var_init (lto_file *file, tree var);
+
 /* The vtable for ELF input files.  */
 static const lto_file_vtable lto_elf_file_vtable = {
   lto_elf_map_fn_body,
-  lto_elf_unmap_fn_body
+  lto_elf_unmap_fn_body,
+  lto_elf_read_var_init
 };
 
+/* Return the section header for SECTION.  The return value is never
+   NULL.  Call lto_elf_free_shdr to release the memory allocated.  */
+static Elf64_Shdr *
+lto_elf_get_shdr (lto_elf_file *elf_file,
+		  Elf_Scn *section)
+{
+  Elf64_Shdr *shdr;
+
+  switch (elf_file->bits)
+    {
+    case 32:
+      {
+	Elf32_Shdr *shdr32;
+	/* Read the 32-bit section header.  */
+	shdr32 = elf32_getshdr (section);
+	if (!shdr32)
+	  fatal_error ("could not read section header: %s",
+		       elf_errmsg (0));
+	/* Transform it into a 64-bit section header.  */
+	shdr = XNEW (Elf64_Shdr);
+	shdr->sh_name = shdr32->sh_name;
+	shdr->sh_type = shdr32->sh_type;
+	shdr->sh_flags = shdr32->sh_flags;
+	shdr->sh_addr = shdr32->sh_addr;
+	shdr->sh_offset = shdr32->sh_offset;
+	shdr->sh_size = shdr32->sh_size;
+	shdr->sh_link = shdr32->sh_link;
+	shdr->sh_info = shdr32->sh_info;
+	shdr->sh_addralign = shdr32->sh_addralign;
+	shdr->sh_entsize  = shdr32->sh_entsize;
+	break;
+      }
+      break;
+    case 64:
+      shdr = elf64_getshdr (section);
+      if (!shdr)
+	fatal_error ("could not read section header: %s",
+		     elf_errmsg (0));
+      break;
+    default:
+      gcc_unreachable();
+    }
+
+  return shdr;
+}
+
+/* Free SHDR, previously allocated by lto_elf_get_shdr.  */
+static void
+lto_elf_free_shdr (lto_elf_file *elf_file, Elf64_Shdr *shdr)
+{
+  if (elf_file->bits != 64)
+    free (shdr);
+}
+
 /* A helper function to find the section named SECTION_NAME in ELF_FILE, and
    return its data.  Emits an appropriate error message and returns NULL
    if a unique section with that name is not found.  */
@@ -74,13 +138,13 @@ lto_elf_find_section_data (lto_elf_file 
 {
   Elf_Scn *section, *result;
   Elf_Data *data;
-  size_t bits = elf_file->bits;
 
   result = NULL;
   for (section = elf_getscn (elf_file->elf, 0);
        section;
        section = elf_nextscn (elf_file->elf, section)) 
     {
+      Elf64_Shdr *shdr;
       size_t offset;
       const char *name;
 
@@ -90,34 +154,12 @@ lto_elf_find_section_data (lto_elf_file 
 	  return NULL;
 	}
 
-#define ELF_GET_SECTION_HEADER_NAME(N)					 \
-      do {								 \
-	Elf##N##_Shdr *section_header;					 \
-	section_header = elf##N##_getshdr (section);			 \
-	if (!section_header)						 \
-	  {								 \
-	    error ("could not read section header: %s", elf_errmsg (0)); \
-	    return NULL;						 \
-	  }								 \
-	offset = section_header->sh_name;				 \
-      } while (false)
-
-      switch (bits)
-	{
-	case 32:
-	  ELF_GET_SECTION_HEADER_NAME(32); 
-	  break;
-	case 64:
-	  ELF_GET_SECTION_HEADER_NAME(64);
-	  break;
-	default:
-	  gcc_unreachable ();
-	}
-
-#undef ELF_GET_SECTION_HEADER_NAME
-
       /* Get the name of this section.  */
-      name = elf_strptr (elf_file->elf, elf_file->string_table_section_index, 
+      shdr = lto_elf_get_shdr (elf_file, section);
+      offset = shdr->sh_name;
+      lto_elf_free_shdr (elf_file, shdr);
+      name = elf_strptr (elf_file->elf, 
+			 elf_file->sec_strtab,
 			 offset);
       if (!name)
 	{
@@ -153,13 +195,110 @@ lto_elf_find_section_data (lto_elf_file 
   return data;
 }
 
+/* Read the ELF symbol table from ELF_FILE.  */
+static void
+lto_elf_read_symtab (lto_elf_file *elf_file)
+{
+  Elf_Scn *section;
+  Elf64_Shdr *shdr;
+
+  /* Iterate over the section table until we find one with type
+     SHT_SYMTAB.  */
+  for (section = elf_getscn (elf_file->elf, 0);
+       section;
+       section = elf_nextscn (elf_file->elf, section))
+    {
+      shdr = lto_elf_get_shdr (elf_file, section);
+      if (shdr->sh_type == SHT_SYMTAB)
+	{
+	  /* We have found the symbol table.  */
+	  elf_file->symtab = elf_getdata (section, NULL);
+	  elf_file->strtab = shdr->sh_link;
+	}
+      lto_elf_free_shdr (elf_file, shdr);
+    }
+}
+
+/* Return the ELF symbol entry for NAME, or NULL if none.  The caller
+   must call lto_elf_free_sym when done with the value returned.  */
+static Elf64_Sym *
+lto_elf_lookup_sym (lto_elf_file *elf_file,
+		    const char *name)
+{
+  const char *first_sym;
+  const char *last_sym;
+  const char *ptr;
+  size_t sym_size;
+  Elf64_Sym *sym;
+
+  gcc_assert (name);
+
+  first_sym = (const char *) elf_file->symtab->d_buf;
+  last_sym = first_sym + elf_file->symtab->d_size;
+  sym_size = ((elf_file->bits == 32) 
+	      ? sizeof (Elf32_Sym)
+	      : sizeof (Elf64_Sym));
+  for (ptr = first_sym; ptr < last_sym; ptr += sym_size)
+    {
+      Elf64_Word sym_name_offset;
+      Elf32_Sym *sym32;
+      const char *sym_name;
+
+      /* Get the ELF symbol entry.  */
+      if (elf_file->bits == 32)
+	{
+	  sym = NULL;
+	  sym32 = (Elf32_Sym *) ptr;
+	  sym_name_offset = sym32->st_name;
+	}
+      else
+	{
+	  sym = (Elf64_Sym *) ptr;
+	  sym32 = NULL;
+	  sym_name_offset = sym->st_name;
+	}
+      /* If the symbol has no name, it cannot be the one we want.  */
+      if (!sym_name_offset)
+	continue;
+      /* Look up the symbol name.  */
+      sym_name = elf_strptr (elf_file->elf,
+			     elf_file->strtab,
+			     sym_name_offset);
+      /* Check to see if it is the one we want.  */
+      if (strcmp (sym_name, name) != 0)
+	continue;
+      /* We have a match.  */
+      if (elf_file->bits == 32)
+	{
+	  sym = XNEW (Elf64_Sym);
+	  sym->st_name = sym32->st_name;
+	  sym->st_value = sym32->st_value;
+	  sym->st_size = sym32->st_size;
+	  sym->st_info = sym32->st_info;
+	  sym->st_other = sym32->st_other;
+	  sym->st_shndx = sym32->st_shndx;
+	}
+      return sym;
+    }
+
+  return NULL;
+}
+
+/* Free SYM, previously allocated by lto_elf_lookup_sym.  */
+static void
+lto_elf_free_sym (lto_elf_file *elf_file, 
+		  Elf64_Sym *sym)
+{
+  if (elf_file->bits == 32)
+    free (sym);
+}
+
 lto_file *
 lto_elf_file_open (const char *filename)
 {
   lto_elf_file *elf_file;
   size_t bits;
   const char *elf_ident;
-  Elf_Scn *string_table_section;
   Elf_Data *data;
   lto_file *result;
   lto_fd *fd;
@@ -251,14 +390,11 @@ lto_elf_file_open (const char *filename)
 #undef ELF_CHECK_FILE_TYPE
 
   /* Read the string table used for section header names.  */
-  if (elf_getshstrndx (elf_file->elf, &elf_file->string_table_section_index) == -1)
+  if (elf_getshstrndx (elf_file->elf, &elf_file->sec_strtab) == -1)
     {
       error ("could not locate ELF string table: %s", elf_errmsg (0));
       goto fail;
     }
-  string_table_section = elf_getscn (elf_file->elf, 
-				     elf_file->string_table_section_index);
-
   /* Find the .debug_info and .debug_abbrev sections.  */
   data = lto_elf_find_section_data (elf_file, ".debug_info");
   if (!data)
@@ -274,6 +410,9 @@ lto_elf_file_open (const char *filename)
   fd->start = (const char *) data->d_buf;
   fd->end = fd->start + data->d_size;
 
+  /* Read the ELF symbol table.  */
+  lto_elf_read_symtab (elf_file);
+
   return result;
 
  fail:
@@ -316,3 +455,115 @@ lto_elf_unmap_fn_body (lto_file *file AT
 {
   return;
 }
+
+/* Build an initializer of the indicated TYPE from the DATA stored in
+   the object file.  */
+static tree
+lto_elf_build_init (lto_elf_file *elf_file ATTRIBUTE_UNUSED,
+		    tree type,
+		    const uint8_t *data)
+{
+  tree init;
+
+  init = error_mark_node;
+  if (AGGREGATE_TYPE_P (type))
+    sorry ("initializers for aggregate types");
+  else if (TREE_CODE (type) == COMPLEX_TYPE)
+    sorry ("initializers for complex types");
+  else if (INTEGRAL_TYPE_P (type))
+    {
+      unsigned HOST_WIDE_INT low;
+      unsigned HOST_WIDE_INT high;
+      HOST_WIDE_INT size;
+      int i;
+
+      low = 0;
+      high = 0;
+      size = int_size_in_bytes (type);
+      gcc_assert (size != -1);
+      if ((size_t) size > sizeof (low))
+	sorry ("multi-word integral initializers");
+      /* Read the initializer, swapping bytes if necessary.  */
+      for (i = 0; i < size; ++i)
+	{
+	  uint8_t byte;
+	  byte = *data++;
+	  if (!BYTES_BIG_ENDIAN)
+	    low |= byte << (HOST_BITS_PER_CHAR * i);
+	  else
+	    low |= byte << (HOST_BITS_PER_CHAR * (size - 1 - i));
+	}
+      /* Create the INTEGER_CST.  */
+      init = build_int_cst_wide_type (type, low, high);
+    }
+  else
+    sorry ("initializers for other types");
+
+  return init;
+}
+
+void
+lto_elf_read_var_init (lto_file *file,
+		       tree var)
+{
+  lto_elf_file *elf_file;
+  const char *name;
+  Elf64_Sym *sym;
+
+  elf_file = (lto_elf_file *) file;
+  /* Find the ELF symbol table entry for VAR.  */
+  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (var));
+  sym = lto_elf_lookup_sym (elf_file, name);
+  /* This is an initialized variable so it must be present in the ELF
+     file.  */
+  if (!sym)
+    fatal_error ("ELF symbol table does not contain %qs", name);
+  /* A VAR_DECL should always be an STT_OBJECT symbol.  */
+  if (ELF64_ST_TYPE (sym->st_info) != STT_OBJECT)
+    fatal_error ("ELF symbol for variable %qs is not %qs",
+		 name, "STT_OBJECT");
+  switch (sym->st_shndx)
+    {
+    case SHN_ABS:
+      /* The input is a relocatable object so the symbol should not
+	 have an absolute address.  */
+      fatal_error ("ELF symbol for defined variable %qs is %qs",
+		   name, "SHN_ABS");
+      break;
+    case SHN_UNDEF:
+      /* This function is only called for variables with initializers
+	 which must, therefore, be defined.  */
+      fatal_error ("ELF symbol for defined variable %qs is %qs",
+		   name, "SHN_UNDEF");
+      break;
+    case SHN_COMMON:
+      /* The symbol is zero-initialized.  We do not need to explicitly
+	 represent the initializer.  */
+      break;
+    case SHN_XINDEX:
+      sorry ("support for SHN_XINDEX");
+      break;
+    default:
+      {
+	Elf_Scn *section;
+	uint64_t offset;
+	Elf_Data *data;
+	tree init;
+
+	/* The location of the data is given as a section-relative
+	   offset.  */
+	section = elf_getscn (elf_file->elf, sym->st_shndx);
+	offset = (uint64_t) sym->st_value;
+	data = elf_rawdata (section, NULL);
+	init = lto_elf_build_init (elf_file,
+				   TREE_TYPE (var),
+				   (uint8_t *) data->d_buf + offset);
+	DECL_INITIAL (var) = init;
+      }
+      break;
+    }
+  /* We're now done with the symbol.  */
+  lto_elf_free_sym (elf_file, sym);
+
+  return;
+}
Index: lto.h
===================================================================
--- lto.h	(revision 126102)
+++ lto.h	(working copy)
@@ -89,6 +89,9 @@ typedef struct lto_file_vtable
      MAP_FN_BODY, with the same value of FN.  Release any resources
      allocated by MAP_FN_BODY.  */
   void (*unmap_fn_body)(lto_file *file, const char *fn, const void *data);
+  /* VAR is an initialized variable.  Set DECL_INITIAL for VAR to the
+     appropriate initializer.  */
+  void (*read_var_init)(lto_file *file, tree var);
 } lto_file_vtable;
 
 /* An input file.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]