This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[LTO] PATCH: Read integral initializers
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 28 Jun 2007 22:58:24 -0700
- Subject: [LTO] PATCH: Read integral initializers
- Reply-to: mark at codesourcery dot com
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. */