This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
More than 64k ELF sections.
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: binutils at sources dot redhat dot com
- Date: Tue, 11 Dec 2001 15:03:34 +1030
- Subject: More than 64k ELF sections.
This is the first step in teaching binutils how to handle greater than
64k elf sections. The second part, which I've yet to write, will deal
with symbol st_shndx.
bfd/ChangeLog
* elfcode.h (elf_swap_ehdr_out): Adjust value written for e_shnum
and e_shstrndx if out of range.
(elf_object_p): Read extended values for e_shnum and e_shstrndx
from the first section header. Allocate space in elf_elfsections
for reserved sections and set to NULLs.
(elf_write_shdrs_and_ehdr): Set overflow fields in first section
header. Skip reserved sections in elf_elfsections. Remove
duplicate size calculation.
binutils/ChangeLog
* readelf.c (process_file_header): Print extended e_shnum and
e_shdtrndx values. Set elf_header values for same.
(get_32bit_section_headers): Add "num" arg to read "num" headers.
(get_64bit_section_headers): Likewise.
(process_section_headers): Update calls.
(get_file_header): Call get_32bit_section_headers or 64bit variant.
include/elf/ChangeLog
* common.h (SHN_XINDEX): Comment typo fix.
* internal.h (Elf_Internal_Ehdr): Change existing "unsigned short"
size, count and index fields to "unsigned int".
--
Alan Modra
Index: bfd/elfcode.h
===================================================================
RCS file: /cvs/src/src/bfd/elfcode.h,v
retrieving revision 1.24
diff -u -p -r1.24 elfcode.h
--- elfcode.h 2001/11/15 01:34:10 1.24
+++ elfcode.h 2001/12/11 02:54:01
@@ -277,6 +277,7 @@ elf_swap_ehdr_out (abfd, src, dst)
const Elf_Internal_Ehdr *src;
Elf_External_Ehdr *dst;
{
+ unsigned int tmp;
int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma;
memcpy (dst->e_ident, src->e_ident, EI_NIDENT);
/* note that all elements of dst are *arrays of unsigned char* already... */
@@ -294,8 +295,14 @@ elf_swap_ehdr_out (abfd, src, dst)
H_PUT_16 (abfd, src->e_phentsize, dst->e_phentsize);
H_PUT_16 (abfd, src->e_phnum, dst->e_phnum);
H_PUT_16 (abfd, src->e_shentsize, dst->e_shentsize);
- H_PUT_16 (abfd, src->e_shnum, dst->e_shnum);
- H_PUT_16 (abfd, src->e_shstrndx, dst->e_shstrndx);
+ tmp = src->e_shnum;
+ if (tmp >= SHN_LORESERVE)
+ tmp = 0;
+ H_PUT_16 (abfd, tmp, dst->e_shnum);
+ tmp = src->e_shstrndx;
+ if (tmp >= SHN_LORESERVE)
+ tmp = SHN_XINDEX;
+ H_PUT_16 (abfd, tmp, dst->e_shstrndx);
}
/* Translate an ELF section header table entry in external format into an
@@ -494,6 +501,7 @@ elf_object_p (abfd)
Elf_External_Ehdr x_ehdr; /* Elf file header, external form */
Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */
Elf_External_Shdr x_shdr; /* Section header table entry, external form */
+ Elf_Internal_Shdr i_shdr;
Elf_Internal_Shdr *i_shdrp = NULL; /* Section header table, internal form */
unsigned int shindex;
char *shstrtab; /* Internal copy of section header stringtab */
@@ -634,27 +642,65 @@ elf_object_p (abfd)
/* Remember the entry point specified in the ELF file header. */
bfd_set_start_address (abfd, i_ehdrp->e_entry);
+ /* Seek to the section header table in the file. */
+ if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_shoff, SEEK_SET) != 0)
+ goto got_no_match;
+
+ /* Read the first section header at index 0, and convert to internal
+ form. */
+ if (bfd_bread ((PTR) & x_shdr, (bfd_size_type) sizeof x_shdr, abfd)
+ != sizeof (x_shdr))
+ goto got_no_match;
+ elf_swap_shdr_in (abfd, &x_shdr, &i_shdr);
+
+ /* If the section count is zero, the actual count is in the first
+ section header. */
+ if (i_ehdrp->e_shnum == 0)
+ i_ehdrp->e_shnum = i_shdr.sh_size;
+
+ /* And similarly for the string table index. */
+ if (i_ehdrp->e_shstrndx == SHN_XINDEX)
+ i_ehdrp->e_shstrndx = i_shdr.sh_link;
+
/* Allocate space for a copy of the section header table in
- internal form, seek to the section header table in the file,
- read it in, and convert it to internal form. */
+ internal form. */
if (i_ehdrp->e_shnum != 0)
{
+ Elf_Internal_Shdr *shdrp;
+
amt = sizeof (*i_shdrp) * i_ehdrp->e_shnum;
i_shdrp = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt);
+ if (!i_shdrp)
+ goto got_no_match;
amt = sizeof (i_shdrp) * i_ehdrp->e_shnum;
+ if (i_ehdrp->e_shnum > SHN_LORESERVE)
+ amt += sizeof (i_shdrp) * (SHN_HIRESERVE + 1 - SHN_LORESERVE);
elf_elfsections (abfd) = (Elf_Internal_Shdr **) bfd_alloc (abfd, amt);
- if (!i_shdrp || !elf_elfsections (abfd))
+ if (!elf_elfsections (abfd))
goto got_no_match;
- if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_shoff, SEEK_SET) != 0)
- goto got_no_match;
+
+ memcpy (i_shdrp, &i_shdr, sizeof (*i_shdrp));
+ shdrp = i_shdrp;
+ shindex = 0;
+ if (i_ehdrp->e_shnum > SHN_LORESERVE)
+ {
+ for ( ; shindex < SHN_LORESERVE; shindex++)
+ elf_elfsections (abfd)[shindex] = shdrp++;
+ for ( ; shindex < SHN_HIRESERVE + 1; shindex++)
+ elf_elfsections (abfd)[shindex] = NULL;
+ }
+ for ( ; shindex < i_ehdrp->e_shnum; shindex++)
+ elf_elfsections (abfd)[shindex] = shdrp++;
}
- for (shindex = 0; shindex < i_ehdrp->e_shnum; shindex++)
+
+ /* Read in the rest of the section header table and convert it to
+ internal form. */
+ for (shindex = 1; shindex < i_ehdrp->e_shnum; shindex++)
{
if (bfd_bread ((PTR) & x_shdr, (bfd_size_type) sizeof x_shdr, abfd)
!= sizeof (x_shdr))
goto got_no_match;
elf_swap_shdr_in (abfd, &x_shdr, i_shdrp + shindex);
- elf_elfsections (abfd)[shindex] = i_shdrp + shindex;
/* If the section is loaded, but not page aligned, clear
D_PAGED. */
@@ -987,21 +1033,30 @@ elf_write_shdrs_and_ehdr (abfd)
|| bfd_bwrite ((PTR) & x_ehdr, amt, abfd) != amt)
return false;
+ /* Some fields in the first section header handle overflow of ehdr
+ fields. */
+ if (i_ehdrp->e_shnum >= SHN_LORESERVE)
+ i_shdrp[0]->sh_size = i_ehdrp->e_shnum;
+ if (i_ehdrp->e_shstrndx >= SHN_LORESERVE)
+ i_shdrp[0]->sh_link = i_ehdrp->e_shstrndx;
+
/* at this point we've concocted all the ELF sections... */
- amt = sizeof (*x_shdrp) * i_ehdrp->e_shnum;
+ amt = i_ehdrp->e_shnum;
+ amt *= sizeof (*x_shdrp);
x_shdrp = (Elf_External_Shdr *) bfd_alloc (abfd, amt);
if (!x_shdrp)
return false;
- for (count = 0; count < i_ehdrp->e_shnum; count++)
+ for (count = 0; count < i_ehdrp->e_shnum; i_shdrp++, count++)
{
#if DEBUG & 2
- elf_debug_section (count, i_shdrp[count]);
+ elf_debug_section (count, *i_shdrp);
#endif
- elf_swap_shdr_out (abfd, i_shdrp[count], x_shdrp + count);
+ elf_swap_shdr_out (abfd, *i_shdrp, x_shdrp + count);
+
+ if (count == SHN_LORESERVE - 1)
+ i_shdrp += SHN_HIRESERVE + 1 - SHN_LORESERVE;
}
- amt = i_ehdrp->e_shnum;
- amt *= sizeof (*x_shdrp);
if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_shoff, SEEK_SET) != 0
|| bfd_bwrite ((PTR) x_shdrp, amt, abfd) != amt)
return false;
Index: binutils/readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.137
diff -u -p -r1.137 readelf.c
--- readelf.c 2001/12/08 03:45:51 1.137
+++ readelf.c 2001/12/11 02:54:30
@@ -197,8 +197,8 @@ static int process_file
static int process_relocs PARAMS ((FILE *));
static int process_version_sections PARAMS ((FILE *));
static char * get_ver_flags PARAMS ((unsigned int));
-static int get_32bit_section_headers PARAMS ((FILE *));
-static int get_64bit_section_headers PARAMS ((FILE *));
+static int get_32bit_section_headers PARAMS ((FILE *, unsigned int));
+static int get_64bit_section_headers PARAMS ((FILE *, unsigned int));
static int get_32bit_program_headers PARAMS ((FILE *, Elf_Internal_Phdr *));
static int get_64bit_program_headers PARAMS ((FILE *, Elf_Internal_Phdr *));
static int get_file_header PARAMS ((FILE *));
@@ -2442,12 +2442,28 @@ process_file_header ()
(long) elf_header.e_phnum);
printf (_(" Size of section headers: %ld (bytes)\n"),
(long) elf_header.e_shentsize);
- printf (_(" Number of section headers: %ld\n"),
+ printf (_(" Number of section headers: %ld"),
(long) elf_header.e_shnum);
- printf (_(" Section header string table index: %ld\n"),
+ if (section_headers != NULL && elf_header.e_shnum == 0)
+ printf (" (%ld)", (long) section_headers[0].sh_size);
+ putc ('\n', stdout);
+ printf (_(" Section header string table index: %ld"),
(long) elf_header.e_shstrndx);
+ if (section_headers != NULL && elf_header.e_shstrndx == SHN_XINDEX)
+ printf (" (%ld)", (long) section_headers[0].sh_link);
+ putc ('\n', stdout);
}
+ if (section_headers != NULL)
+ {
+ if (elf_header.e_shnum == 0)
+ elf_header.e_shnum = section_headers[0].sh_size;
+ if (elf_header.e_shstrndx == SHN_XINDEX)
+ elf_header.e_shstrndx = section_headers[0].sh_link;
+ free (section_headers);
+ section_headers = NULL;
+ }
+
return 1;
}
@@ -2760,8 +2776,9 @@ process_program_headers (file)
static int
-get_32bit_section_headers (file)
+get_32bit_section_headers (file, num)
FILE * file;
+ unsigned int num;
{
Elf32_External_Shdr * shdrs;
Elf32_Internal_Shdr * internal;
@@ -2769,13 +2786,13 @@ get_32bit_section_headers (file)
shdrs = ((Elf32_External_Shdr *)
get_data (NULL, file, elf_header.e_shoff,
- elf_header.e_shentsize * elf_header.e_shnum,
+ elf_header.e_shentsize * num,
_("section headers")));
if (!shdrs)
return 0;
- section_headers = (Elf_Internal_Shdr *) malloc
- (elf_header.e_shnum * sizeof (Elf_Internal_Shdr));
+ section_headers = ((Elf_Internal_Shdr *)
+ malloc (num * sizeof (Elf_Internal_Shdr)));
if (section_headers == NULL)
{
@@ -2784,7 +2801,7 @@ get_32bit_section_headers (file)
}
for (i = 0, internal = section_headers;
- i < elf_header.e_shnum;
+ i < num;
i ++, internal ++)
{
internal->sh_name = BYTE_GET (shdrs[i].sh_name);
@@ -2805,8 +2822,9 @@ get_32bit_section_headers (file)
}
static int
-get_64bit_section_headers (file)
+get_64bit_section_headers (file, num)
FILE * file;
+ unsigned int num;
{
Elf64_External_Shdr * shdrs;
Elf64_Internal_Shdr * internal;
@@ -2814,13 +2832,13 @@ get_64bit_section_headers (file)
shdrs = ((Elf64_External_Shdr *)
get_data (NULL, file, elf_header.e_shoff,
- elf_header.e_shentsize * elf_header.e_shnum,
+ elf_header.e_shentsize * num,
_("section headers")));
if (!shdrs)
return 0;
- section_headers = (Elf_Internal_Shdr *) malloc
- (elf_header.e_shnum * sizeof (Elf_Internal_Shdr));
+ section_headers = ((Elf_Internal_Shdr *)
+ malloc (num * sizeof (Elf_Internal_Shdr)));
if (section_headers == NULL)
{
@@ -2829,7 +2847,7 @@ get_64bit_section_headers (file)
}
for (i = 0, internal = section_headers;
- i < elf_header.e_shnum;
+ i < num;
i ++, internal ++)
{
internal->sh_name = BYTE_GET (shdrs[i].sh_name);
@@ -3007,10 +3025,10 @@ process_section_headers (file)
if (is_32bit_elf)
{
- if (! get_32bit_section_headers (file))
+ if (! get_32bit_section_headers (file, elf_header.e_shnum))
return 0;
}
- else if (! get_64bit_section_headers (file))
+ else if (! get_64bit_section_headers (file, elf_header.e_shnum))
return 0;
/* Read in the string table, so that we have names to display. */
@@ -9185,6 +9203,13 @@ get_file_header (file)
elf_header.e_shnum = BYTE_GET (ehdr64.e_shnum);
elf_header.e_shstrndx = BYTE_GET (ehdr64.e_shstrndx);
}
+
+ /* There may be some extensions in the first section header. Don't
+ bomb if we can't read it. */
+ if (is_32bit_elf)
+ get_32bit_section_headers (file, 1);
+ else
+ get_64bit_section_headers (file, 1);
return 1;
}
Index: include/elf/common.h
===================================================================
RCS file: /cvs/src/src/include/elf/common.h,v
retrieving revision 1.36
diff -u -p -r1.36 common.h
--- common.h 2001/12/08 03:46:03 1.36
+++ common.h 2001/12/11 02:54:53
@@ -405,7 +405,7 @@ Foundation, Inc., 59 Temple Place - Suit
#define SHN_HIOS 0xFF3F /* OS specific semantics, hi */
#define SHN_ABS 0xFFF1 /* Associated symbol is absolute */
#define SHN_COMMON 0xFFF2 /* Associated symbol is in common */
-#define SHN_XINDEX 0xFFFF /* Section index it held elsewhere */
+#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */
#define SHN_HIRESERVE 0xFFFF /* End range of reserved indices */
/* The following constants control how a symbol may be accessed once it has
Index: include/elf/internal.h
===================================================================
RCS file: /cvs/src/src/include/elf/internal.h,v
retrieving revision 1.6
diff -u -p -r1.6 internal.h
--- internal.h 2001/10/23 04:42:12 1.6
+++ internal.h 2001/12/11 02:54:53
@@ -50,12 +50,12 @@ typedef struct elf_internal_ehdr {
unsigned long e_flags; /* Processor-specific flags */
unsigned short e_type; /* Identifies object file type */
unsigned short e_machine; /* Specifies required architecture */
- unsigned short e_ehsize; /* ELF header size in bytes */
- unsigned short e_phentsize; /* Program header table entry size */
- unsigned short e_phnum; /* Program header table entry count */
- unsigned short e_shentsize; /* Section header table entry size */
- unsigned short e_shnum; /* Section header table entry count */
- unsigned short e_shstrndx; /* Section header string table index */
+ unsigned int e_ehsize; /* ELF header size in bytes */
+ unsigned int e_phentsize; /* Program header table entry size */
+ unsigned int e_phnum; /* Program header table entry count */
+ unsigned int e_shentsize; /* Section header table entry size */
+ unsigned int e_shnum; /* Section header table entry count */
+ unsigned int e_shstrndx; /* Section header string table index */
} Elf_Internal_Ehdr;
#define elf32_internal_ehdr elf_internal_ehdr