diff options
Diffstat (limited to 'bfd/elf.c')
-rw-r--r-- | bfd/elf.c | 312 |
1 files changed, 264 insertions, 48 deletions
@@ -68,9 +68,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ */ -#include <ansidecl.h> -#include <sysdep.h> #include "bfd.h" +#include "sysdep.h" #include "libbfd.h" #include "obstack.h" #include "elf-common.h" @@ -128,6 +127,26 @@ DEFUN(bfd_swap_shdr_in,(abfd, src, dst), } +/* Translate an ELF program header table entry in external format into an + ELF program header table entry in internal format. */ + +static void +DEFUN(bfd_swap_phdr_in,(abfd, src, dst), + bfd *abfd AND + Elf_External_Phdr *src AND + Elf_Internal_Phdr *dst) +{ + dst -> p_type = bfd_h_get_32 (abfd, (bfd_byte *) src -> p_type); + dst -> p_offset = bfd_h_get_32 (abfd, (bfd_byte *) src -> p_offset); + dst -> p_vaddr = bfd_h_get_32 (abfd, (bfd_byte *) src -> p_vaddr); + dst -> p_paddr = bfd_h_get_32 (abfd, (bfd_byte *) src -> p_paddr); + dst -> p_filesz = bfd_h_get_32 (abfd, (bfd_byte *) src -> p_filesz); + dst -> p_memsz = bfd_h_get_32 (abfd, (bfd_byte *) src -> p_memsz); + dst -> p_flags = bfd_h_get_32 (abfd, (bfd_byte *) src -> p_flags); + dst -> p_align = bfd_h_get_32 (abfd, (bfd_byte *) src -> p_align); +} + + /* Create a new bfd section from an ELF section header. */ static boolean @@ -172,6 +191,91 @@ DEFUN(bfd_section_from_shdr, (abfd, hdr, shstrtab), return (true); } +/* Create a new bfd section from an ELF program header. + + Since program segments have no names, we generate a synthetic name + of the form segment<NUM>, where NUM is generally the index in the + program header table. For segments that are split (see below) we + generate the names segment<NUM>a and segment<NUM>b. + + Note that some program segments may have a file size that is different than + (less than) the memory size. All this means is that at execution the + system must allocate the amount of memory specified by the memory size, + but only initialize it with the first "file size" bytes read from the + file. This would occur for example, with program segments consisting + of combined data+bss. + + To handle the above situation, this routine generates TWO bfd sections + for the single program segment. The first has the length specified by + the file size of the segment, and the second has the length specified + by the difference between the two sizes. In effect, the segment is split + into it's initialized and uninitialized parts. + + */ + +static boolean +DEFUN(bfd_section_from_phdr, (abfd, hdr, index), + bfd *abfd AND + Elf_Internal_Phdr *hdr AND + int index) +{ + asection *newsect; + char *name; + char namebuf[64]; + int split; + + split = ((hdr -> p_memsz > 0) && + (hdr -> p_filesz > 0) && + (hdr -> p_memsz > hdr -> p_filesz)); + sprintf (namebuf, split ? "segment%da" : "segment%d", index); + name = bfd_alloc (abfd, strlen (namebuf) + 1); + (void) strcpy (name, namebuf); + newsect = bfd_make_section (abfd, name); + newsect -> vma = hdr -> p_vaddr; + newsect -> size = hdr -> p_filesz; + newsect -> filepos = hdr -> p_offset; + newsect -> flags |= SEC_HAS_CONTENTS; + if (hdr -> p_type == PT_LOAD) + { + newsect -> flags |= SEC_ALLOC; + newsect -> flags |= SEC_LOAD; + if (hdr -> p_flags & PF_X) + { + /* FIXME: all we known is that it has execute PERMISSION, + may be data. */ + newsect -> flags |= SEC_CODE; + } + } + if (!(hdr -> p_flags & PF_W)) + { + newsect -> flags |= SEC_READONLY; + } + + if (split) + { + sprintf (namebuf, "segment%db", index); + name = bfd_alloc (abfd, strlen (namebuf) + 1); + (void) strcpy (name, namebuf); + newsect = bfd_make_section (abfd, name); + newsect -> vma = hdr -> p_vaddr + hdr -> p_filesz; + newsect -> size = hdr -> p_memsz - hdr -> p_filesz; + if (hdr -> p_type == PT_LOAD) + { + newsect -> flags |= SEC_ALLOC; + if (hdr -> p_flags & PF_X) + { + newsect -> flags |= SEC_CODE; + } + } + if (!(hdr -> p_flags & PF_W)) + { + newsect -> flags |= SEC_READONLY; + } + } + + return (true); +} + /* Begin processing a given object. First we validate the file by reading in the ELF header and checking @@ -241,7 +345,9 @@ wrong: /* Now that we know the byte order, swap in the rest of the header */ bfd_swap_ehdr_in (abfd, &x_ehdr, &i_ehdr); - if (x_ehdr.e_shoff == 0) + + /* If there is no section header table, we're hosed. */ + if (i_ehdr.e_shoff == 0) goto wrong; if (i_ehdr.e_type == ET_EXEC || i_ehdr.e_type == ET_DYN) @@ -316,6 +422,125 @@ wrong: return (abfd->xvec); } +/* Core files are simply standard ELF formatted files that partition + the file using the execution view of the file (program header table) + rather than the linking view. In fact, there is no section header + table in a core file. + */ + +static bfd_target * +DEFUN (elf_core_file_p, (abfd), bfd *abfd) +{ + Elf_External_Ehdr x_ehdr; /* Elf file header, external form */ + Elf_Internal_Ehdr i_ehdr; /* Elf file header, internal form */ + Elf_External_Phdr *x_phdr; /* Program header table, external form */ + Elf_Internal_Phdr *i_phdr; /* Program header table, internal form */ + int phindex; + + /* Read in the ELF header in external format. */ + + if (bfd_read ((PTR) &x_ehdr, sizeof (x_ehdr), 1, abfd) != sizeof (x_ehdr)) + { + bfd_error = system_call_error; + return (NULL); + } + + /* Now check to see if we have a valid ELF file, and one that BFD can + make use of. The magic number must match, the address size ('class') + and byte-swapping must match our XVEC entry, and it must have a + program header table (FIXME: See comments re segments at top of this + file). */ + + if (x_ehdr.e_ident[EI_MAG0] != ELFMAG0 || + x_ehdr.e_ident[EI_MAG1] != ELFMAG1 || + x_ehdr.e_ident[EI_MAG2] != ELFMAG2 || + x_ehdr.e_ident[EI_MAG3] != ELFMAG3) + { +wrong: + bfd_error = wrong_format; + return (NULL); + } + + /* FIXME, Check EI_VERSION here ! */ + + switch (x_ehdr.e_ident[EI_CLASS]) { + case ELFCLASSNONE: /* address size not specified */ + goto wrong; /* No support if can't tell address size */ + case ELFCLASS32: /* 32-bit addresses */ + break; + case ELFCLASS64: /* 64-bit addresses */ + goto wrong; /* FIXME: 64 bits not yet supported */ + default: + goto wrong; /* No support if unknown address class */ + } + + /* Switch xvec to match the specified byte order. */ + switch (x_ehdr.e_ident[EI_DATA]) { + case ELFDATA2MSB: /* Big-endian */ + abfd->xvec = &elf_big_vec; + break; + case ELFDATA2LSB: /* Little-endian */ + abfd->xvec = &elf_little_vec; + case ELFDATANONE: /* No data encoding specified */ + default: /* Unknown data encoding specified */ + goto wrong; + } + + /* Now that we know the byte order, swap in the rest of the header */ + bfd_swap_ehdr_in (abfd, &x_ehdr, &i_ehdr); + + /* If there is no program header, or the type is not a core file, then + we are hosed. */ + if (i_ehdr.e_phoff == 0 || i_ehdr.e_type != ET_CORE) + goto wrong; + + /* Allocate space for copies of the program header table in external + and internal form, seek to the program header table in the file, + read it in, and convert it to internal form. As a simple sanity + check, verify that the what BFD thinks is the size of each program + header table entry actually matches the size recorded in the file. */ + + if (i_ehdr.e_phentsize != sizeof (*x_phdr)) + goto wrong; + if ((x_phdr = (Elf_External_Phdr *) + bfd_alloc (abfd, sizeof (*x_phdr) * i_ehdr.e_phnum)) == NULL) + { + bfd_error = no_memory; + return (NULL); + } + if ((i_phdr = (Elf_Internal_Phdr *) + bfd_alloc (abfd, sizeof (*i_phdr) * i_ehdr.e_phnum)) == NULL) + { + bfd_error = no_memory; + return (NULL); + } + if (bfd_seek (abfd, i_ehdr.e_phoff, SEEK_SET) == -1) + { + bfd_error = system_call_error; + return (NULL); + } + for (phindex = 0; phindex < i_ehdr.e_phnum; phindex++) + { + if (bfd_read ((PTR) (x_phdr + phindex), sizeof (*x_phdr), 1, abfd) + != sizeof (*x_phdr)) + { + bfd_error = system_call_error; + return (NULL); + } + bfd_swap_phdr_in (abfd, x_phdr + phindex, i_phdr + phindex); + } + + /* Once all of the program headers have been read and converted, we + can start processing them. */ + + for (phindex = 0; phindex < i_ehdr.e_phnum; phindex++) + { + bfd_section_from_phdr (abfd, i_phdr + phindex, phindex); + } + + return (abfd->xvec); +} + static boolean DEFUN (elf_mkobject, (abfd), bfd *abfd) { @@ -334,39 +559,6 @@ DEFUN (elf_write_object_contents, (abfd), bfd *abfd) return (false); } -static boolean -DEFUN (elf_set_section_contents, (abfd, section, location, offset, count), - bfd *abfd AND - sec_ptr section AND - PTR location AND - file_ptr offset AND - bfd_size_type count) -{ - fprintf (stderr, "elf_set_section_contents unimplemented\n"); - fflush (stderr); - abort (); - return (false); -} - -#define elf_new_section_hook _bfd_dummy_new_section_hook -#define elf_core_file_failing_command _bfd_dummy_core_file_failing_command -#define elf_core_file_failing_signal _bfd_dummy_core_file_failing_signal -#define elf_core_file_matches_executable_p _bfd_dummy_core_file_matches_executable_p -#define elf_slurp_armap bfd_false -#define elf_slurp_extended_name_table _bfd_slurp_extended_name_table -#define elf_truncate_arname bfd_dont_truncate_arname -#define elf_openr_next_archived_file bfd_generic_openr_next_archived_file -#define elf_generic_stat_arch_elt bfd_generic_stat_arch_elt -#define elf_get_section_contents bfd_generic_get_section_contents -#define elf_close_and_cleanup bfd_generic_close_and_cleanup - -#define elf_bfd_debug_info_start bfd_void -#define elf_bfd_debug_info_end bfd_void -#define elf_bfd_debug_info_accumulate (PROTO(void,(*),(bfd*, struct sec *))) bfd_void - -#define elf_write_armap bfd_false - - static unsigned int elf_get_symtab_upper_bound(abfd) bfd *abfd; @@ -427,7 +619,7 @@ DEFUN (elf_print_symbol,(ignore_abfd, filep, symbol, how), bfd *ignore_abfd AND PTR filep AND asymbol *symbol AND - bfd_print_symbol_enum_type how) + bfd_print_symbol_type how) { fprintf (stderr, "elf_print_symbol unimplemented\n"); fflush (stderr); @@ -489,7 +681,7 @@ DEFUN (elf_sizeof_headers, (abfd, reloc), abort (); return (0); } - + /* This structure contains everything that BFD knows about a target. It includes things like its byte order, name, what routines to call to do various operations, etc. Every BFD points to a target structure @@ -498,13 +690,37 @@ DEFUN (elf_sizeof_headers, (abfd, reloc), There are two such structures here: one for big-endian machines and one for little-endian machines. */ +#define elf_core_file_failing_command _bfd_dummy_core_file_failing_command +#define elf_core_file_failing_signal _bfd_dummy_core_file_failing_signal +#define elf_core_file_matches_executable_p _bfd_dummy_core_file_matches_executable_p + +/* Archives are generic or unimplemented. */ +#define elf_slurp_armap bfd_false +#define elf_slurp_extended_name_table _bfd_slurp_extended_name_table +#define elf_truncate_arname bfd_dont_truncate_arname +#define elf_openr_next_archived_file bfd_generic_openr_next_archived_file +#define elf_generic_stat_arch_elt bfd_generic_stat_arch_elt +#define elf_write_armap (PROTO (boolean, (*), \ + (bfd *arch, unsigned int elength, struct orl *map, int orl_count, \ + int stridx))) bfd_false + +/* Ordinary section reading and writing */ +#define elf_new_section_hook _bfd_dummy_new_section_hook +#define elf_get_section_contents bfd_generic_get_section_contents +#define elf_set_section_contents bfd_generic_set_section_contents +#define elf_close_and_cleanup bfd_generic_close_and_cleanup + +#define elf_bfd_debug_info_start bfd_void +#define elf_bfd_debug_info_end bfd_void +#define elf_bfd_debug_info_accumulate (PROTO(void,(*),(bfd*, struct sec *))) bfd_void + bfd_target elf_big_vec = { /* name: identify kind of target */ "elf-big", /* flavour: general indication about file */ - bfd_target_elf_flavour_enum, + bfd_target_elf_flavour, /* byteorder_big_p: data is big endian */ true, @@ -542,10 +758,10 @@ bfd_target elf_big_vec = _do_getb64, _do_putb64, _do_getb32, _do_putb32, _do_getb16, _do_putb16, /* bfd_check_format: check the format of a file being read */ - { _bfd_dummy_target, - elf_object_p, - bfd_generic_archive_p, - _bfd_dummy_target + { _bfd_dummy_target, /* unknown format */ + elf_object_p, /* assembler/linker output (object file) */ + bfd_generic_archive_p, /* an archive */ + elf_core_file_p /* a core file */ }, /* bfd_set_format: set the format of a file being written */ @@ -576,7 +792,7 @@ bfd_target elf_little_vec = "elf-little", /* flavour: general indication about file */ - bfd_target_elf_flavour_enum, + bfd_target_elf_flavour, /* byteorder_big_p: data is big endian */ false, /* Nope -- this one's little endian */ @@ -614,10 +830,10 @@ bfd_target elf_little_vec = _do_getl64, _do_putl64, _do_getl32, _do_putl32, _do_getl16, _do_putl16, /* bfd_check_format: check the format of a file being read */ - { _bfd_dummy_target, - elf_object_p, - bfd_generic_archive_p, - _bfd_dummy_target + { _bfd_dummy_target, /* unknown format */ + elf_object_p, /* assembler/linker output (object file) */ + bfd_generic_archive_p, /* an archive */ + elf_core_file_p /* a core file */ }, /* bfd_set_format: set the format of a file being written */ |