This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils 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]

Target-specific FDE pointer sizes (2/3)


Following up from:

    http://sources.redhat.com/ml/binutils/2005-01/msg00504.html

this patch teaches readelf about the unusal MIPS EABI64 treatment
of FDE addresses.  Specifically, it replaces various:

    is_32bit_elf ? 4 : 8

address size calculations with a global eh_addr_size variable.

As with the bfd patch, we need to distinguish between the official
LP64 ABI and the not-so-official ILP32 variant.  In the case of bfd,
it was important that we get the size right, and we had to punt if
we weren't sure.  In the case of readelf, I think we just want a
"best guess", since we have to output _something_.

The guess depends on the section headers, so eh_addr_size is
initialised in process_section_headers, after the point at
which the section headers have been read.

The patch also changes find_section so that it returns zero-length
sections.  This doesn't affect the existing callers because they are
all followed by calls to get_data, which returns null for zero-length
sections.

I suppose there might be scope for a command-line option to
specify the address size, but I'd rather not add that unless
there's a specific need.  Unmarked ILP32 objects are very much
a legacy here.

Tested on mips64-elf, mips64-linux-gnu and i686-linux-gnu.
The testcase was included in the first message.  OK to install?

Richard


binutils/
	* readelf.c (eh_addr_size): New variable.
	(find_section): Move earlier in file.  Return empty sections too.
	(process_program_headers): Use find_section to find .dynamic.
	(process_section_headers): Initialize eh_addr_size.
	(dump_ia64_unwind, slurp_ia64_unwind_table, ia64_process_unwind)
	(dump_hppa_unwind, slurp_hppa_unwind_table, hppa_process_unwind)
	(display_debug_frames): Use it instead of local addr_size variable.
	(size_of_encoded_value): Get pointer size from eh_addr_size rather
	than is_32bit_elf.

Index: binutils/readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.274
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.274 readelf.c
--- binutils/readelf.c	10 Jan 2005 17:28:37 -0000	1.274
+++ binutils/readelf.c	29 Jan 2005 09:17:40 -0000
@@ -170,6 +170,7 @@ int do_notes;
 int is_32bit_elf;
 int have_frame_base;
 int need_base_address;
+bfd_vma eh_addr_size;
 
 struct group_list
 {
@@ -643,6 +644,20 @@ byte_put_big_endian (unsigned char *fiel
     }
 }
 
+/* Return a pointer to section NAME, or NULL if no such section exists.  */
+
+static Elf_Internal_Shdr *
+find_section (const char *name)
+{
+  unsigned int i;
+
+  for (i = 0; i < elf_header.e_shnum; i++)
+    if (streq (SECTION_NAME (section_headers + i), name))
+      return section_headers + i;
+
+  return NULL;
+}
+
 /* Guess the relocation size commonly used by the specific machines.  */
 
 static int
@@ -3284,15 +3299,9 @@ process_program_headers (FILE *file)
 	  if (section_headers != NULL)
 	    {
 	      Elf_Internal_Shdr *sec;
-	      unsigned int j;
 
-	      for (j = 0, sec = section_headers;
-		   j < elf_header.e_shnum;
-		   j++, sec++)
-		if (streq (SECTION_NAME (sec), ".dynamic"))
-		  break;
-
-	      if (j == elf_header.e_shnum || sec->sh_size == 0)
+	      sec = find_section (".dynamic");
+	      if (sec == NULL || sec->sh_size == 0)
 		{
 		  error (_("no .dynamic section in the dynamic segment"));
 		  break;
@@ -3716,6 +3725,26 @@ process_section_headers (FILE *file)
   dynamic_syminfo = NULL;
   symtab_shndx_hdr = NULL;
 
+  eh_addr_size = is_32bit_elf ? 4 : 8;
+  switch (elf_header.e_machine)
+    {
+    case EM_MIPS:
+    case EM_MIPS_RS3_LE:
+      /* The 64-bit MIPS EABI uses a combination of 32-bit ELF and 64-bit
+	 FDE addresses.  However, the ABI also has a semi-official ILP32
+	 variant for which the normal FDE address size rules apply.
+
+	 GCC 4.0 marks EABI64 objects with a dummy .gcc_compiled_longXX
+	 section, where XX is the size of longs in bits.  Unfortunately,
+	 earlier compilers provided no way of distinguishing ILP32 objects
+	 from LP64 objects, so if there's any doubt, we should assume that
+	 the official LP64 form is being used.  */
+      if ((elf_header.e_flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI64
+	  && find_section (".gcc_compiled_long32") == NULL)
+	eh_addr_size = 8;
+      break;
+    }
+
   for (i = 0, section = section_headers;
        i < elf_header.e_shnum;
        i++, section++)
@@ -4301,12 +4330,9 @@ find_symbol_for_address (Elf_Internal_Sy
 static void
 dump_ia64_unwind (struct ia64_unw_aux_info *aux)
 {
-  bfd_vma addr_size;
   struct ia64_unw_table_entry *tp;
   int in_body;
 
-  addr_size = is_32bit_elf ? 4 : 8;
-
   for (tp = aux->table; tp < aux->table + aux->table_len; ++tp)
     {
       bfd_vma stamp;
@@ -4343,7 +4369,7 @@ dump_ia64_unwind (struct ia64_unw_aux_in
 	      (unsigned long) ((stamp & UNW_FLAG_MASK) >> 32),
 	      UNW_FLAG_EHANDLER (stamp) ? " ehandler" : "",
 	      UNW_FLAG_UHANDLER (stamp) ? " uhandler" : "",
-	      (unsigned long) (addr_size * UNW_LENGTH (stamp)));
+	      (unsigned long) (eh_addr_size * UNW_LENGTH (stamp)));
 
       if (UNW_VER (stamp) != 1)
 	{
@@ -4352,7 +4378,7 @@ dump_ia64_unwind (struct ia64_unw_aux_in
 	}
 
       in_body = 0;
-      for (dp = head + 8; dp < head + 8 + addr_size * UNW_LENGTH (stamp);)
+      for (dp = head + 8; dp < head + 8 + eh_addr_size * UNW_LENGTH (stamp);)
 	dp = unw_decode (dp, in_body, & in_body);
     }
 }
@@ -4362,7 +4388,7 @@ slurp_ia64_unwind_table (FILE *file,
 			 struct ia64_unw_aux_info *aux,
 			 Elf_Internal_Shdr *sec)
 {
-  unsigned long size, addr_size, nrelas, i;
+  unsigned long size, nrelas, i;
   Elf_Internal_Phdr *seg;
   struct ia64_unw_table_entry *tep;
   Elf_Internal_Shdr *relsec;
@@ -4371,8 +4397,6 @@ slurp_ia64_unwind_table (FILE *file,
   Elf_Internal_Sym *sym;
   const char *relname;
 
-  addr_size = is_32bit_elf ? 4 : 8;
-
   /* First, find the starting address of the segment that includes
      this section: */
 
@@ -4403,8 +4427,9 @@ slurp_ia64_unwind_table (FILE *file,
   if (!table)
     return 0;
 
-  tep = aux->table = xmalloc (size / (3 * addr_size) * sizeof (aux->table[0]));
-  for (tp = table; tp < table + size; tp += 3 * addr_size, ++tep)
+  aux->table = xmalloc (size / (3 * eh_addr_size) * sizeof (aux->table[0]));
+  tep = aux->table;
+  for (tp = table; tp < table + size; tp += 3 * eh_addr_size, ++tep)
     {
       tep->start.section = SHN_UNDEF;
       tep->end.section   = SHN_UNDEF;
@@ -4460,9 +4485,9 @@ slurp_ia64_unwind_table (FILE *file,
 	      continue;
 	    }
 
-	  i = rp->r_offset / (3 * addr_size);
+	  i = rp->r_offset / (3 * eh_addr_size);
 
-	  switch (rp->r_offset/addr_size % 3)
+	  switch (rp->r_offset/eh_addr_size % 3)
 	    {
 	    case 0:
 	      aux->table[i].start.section = sym->st_shndx;
@@ -4484,7 +4509,7 @@ slurp_ia64_unwind_table (FILE *file,
       free (rela);
     }
 
-  aux->table_len = size / (3 * addr_size);
+  aux->table_len = size / (3 * eh_addr_size);
   return 1;
 }
 
@@ -4492,13 +4517,11 @@ static int
 ia64_process_unwind (FILE *file)
 {
   Elf_Internal_Shdr *sec, *unwsec = NULL, *strsec;
-  unsigned long i, addr_size, unwcount = 0, unwstart = 0;
+  unsigned long i, unwcount = 0, unwstart = 0;
   struct ia64_unw_aux_info aux;
 
   memset (& aux, 0, sizeof (aux));
 
-  addr_size = is_32bit_elf ? 4 : 8;
-
   for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
     {
       if (sec->sh_type == SHT_SYMTAB)
@@ -4602,7 +4625,7 @@ ia64_process_unwind (FILE *file)
 
 	  printf (_(" at offset 0x%lx contains %lu entries:\n"),
 		  (unsigned long) unwsec->sh_offset,
-		  (unsigned long) (unwsec->sh_size / (3 * addr_size)));
+		  (unsigned long) (unwsec->sh_size / (3 * eh_addr_size)));
 
 	  (void) slurp_ia64_unwind_table (file, & aux, unwsec);
 
@@ -4676,10 +4699,8 @@ struct hppa_unw_aux_info
 static void
 dump_hppa_unwind (struct hppa_unw_aux_info *aux)
 {
-  bfd_vma addr_size;
   struct hppa_unw_table_entry *tp;
 
-  addr_size = is_32bit_elf ? 4 : 8;
   for (tp = aux->table; tp < aux->table + aux->table_len; ++tp)
     {
       bfd_vma offset;
@@ -4746,7 +4767,7 @@ slurp_hppa_unwind_table (FILE *file,
 			 struct hppa_unw_aux_info *aux,
 			 Elf_Internal_Shdr *sec)
 {
-  unsigned long size, unw_ent_size, addr_size, nrelas, i;
+  unsigned long size, unw_ent_size, nrelas, i;
   Elf_Internal_Phdr *seg;
   struct hppa_unw_table_entry *tep;
   Elf_Internal_Shdr *relsec;
@@ -4755,8 +4776,6 @@ slurp_hppa_unwind_table (FILE *file,
   Elf_Internal_Sym *sym;
   const char *relname;
 
-  addr_size = is_32bit_elf ? 4 : 8;
-
   /* First, find the starting address of the segment that includes
      this section.  */
 
@@ -4788,11 +4807,11 @@ slurp_hppa_unwind_table (FILE *file,
   if (!table)
     return 0;
 
-  unw_ent_size = 2 * addr_size + 8;
+  unw_ent_size = 2 * eh_addr_size + 8;
 
   tep = aux->table = xmalloc (size / unw_ent_size * sizeof (aux->table[0]));
 
-  for (tp = table; tp < table + size; tp += (2 * addr_size + 8), ++tep)
+  for (tp = table; tp < table + size; tp += (2 * eh_addr_size + 8), ++tep)
     {
       unsigned int tmp1, tmp2;
 
@@ -4887,7 +4906,7 @@ slurp_hppa_unwind_table (FILE *file,
 
 	  i = rp->r_offset / unw_ent_size;
 
-	  switch ((rp->r_offset % unw_ent_size) / addr_size)
+	  switch ((rp->r_offset % unw_ent_size) / eh_addr_size)
 	    {
 	    case 0:
 	      aux->table[i].start.section = sym->st_shndx;
@@ -4917,13 +4936,11 @@ hppa_process_unwind (FILE *file)
   Elf_Internal_Shdr *unwsec = NULL;
   Elf_Internal_Shdr *strsec;
   Elf_Internal_Shdr *sec;
-  unsigned long addr_size;
   unsigned long i;
 
   memset (& aux, 0, sizeof (aux));
 
   assert (string_table != NULL);
-  addr_size = is_32bit_elf ? 4 : 8;
 
   for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
     {
@@ -4953,7 +4970,7 @@ hppa_process_unwind (FILE *file)
 
 	  printf (_(" at offset 0x%lx contains %lu entries:\n"),
 		  (unsigned long) sec->sh_offset,
-		  (unsigned long) (sec->sh_size / (2 * addr_size + 8)));
+		  (unsigned long) (sec->sh_size / (2 * eh_addr_size + 8)));
 
           slurp_hppa_unwind_table (file, &aux, sec);
 	  if (aux.table_len > 0)
@@ -7050,26 +7067,6 @@ process_extended_line_op (unsigned char 
   return len;
 }
 
-/* Finds section NAME inside FILE and returns a
-   pointer to it, or NULL upon failure.  */
-
-static Elf_Internal_Shdr *
-find_section (const char * name)
-{
-  Elf_Internal_Shdr *sec;
-  unsigned int i;
-
-  for (i = elf_header.e_shnum, sec = section_headers + i - 1;
-       i; --i, --sec)
-    if (streq (SECTION_NAME (sec), name))
-      break;
-
-  if (i && sec && sec->sh_size != 0)
-    return sec;
-
-  return NULL;
-}
-
 static const char *debug_str_contents;
 static bfd_vma debug_str_size;
 
@@ -9913,7 +9910,7 @@ size_of_encoded_value (int encoding)
   switch (encoding & 0x7)
     {
     default:	/* ??? */
-    case 0:	return is_32bit_elf ? 4 : 8;
+    case 0:	return eh_addr_size;
     case 2:	return 2;
     case 3:	return 4;
     case 4:	return 8;
@@ -9947,7 +9944,6 @@ display_debug_frames (Elf_Internal_Shdr 
   int is_eh = streq (SECTION_NAME (section), ".eh_frame");
   int length_return;
   int max_regs = 0;
-  int addr_size = is_32bit_elf ? 4 : 8;
 
   printf (_("The section %s contains:\n"), SECTION_NAME (section));
 
@@ -9962,7 +9958,7 @@ display_debug_frames (Elf_Internal_Shdr 
       int need_col_headers = 1;
       unsigned char *augmentation_data = NULL;
       unsigned long augmentation_data_len = 0;
-      int encoded_ptr_size = addr_size;
+      int encoded_ptr_size = eh_addr_size;
       int offset_size;
       int initial_length_size;
 
@@ -10035,7 +10031,7 @@ display_debug_frames (Elf_Internal_Shdr 
 	    }
 	  else if (streq (fc->augmentation, "eh"))
 	    {
-	      start += addr_size;
+	      start += eh_addr_size;
 	      fc->code_factor = LEB ();
 	      fc->data_factor = SLEB ();
 	      if (version == 1)
@@ -10515,7 +10511,7 @@ display_debug_frames (Elf_Internal_Shdr 
 	      if (! do_debug_frames_interp)
 		{
 		  printf ("  DW_CFA_def_cfa_expression (");
-		  decode_location_expression (start, addr_size, ul, 0);
+		  decode_location_expression (start, eh_addr_size, ul, 0);
 		  printf (")\n");
 		}
 	      fc->cfa_exp = 1;
@@ -10528,7 +10524,7 @@ display_debug_frames (Elf_Internal_Shdr 
 	      if (! do_debug_frames_interp)
 		{
 		  printf ("  DW_CFA_expression: r%ld (", reg);
-		  decode_location_expression (start, addr_size, ul, 0);
+		  decode_location_expression (start, eh_addr_size, ul, 0);
 		  printf (")\n");
 		}
 	      fc->col_type[reg] = DW_CFA_expression;


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