X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=bfd%2Flibbfd.c;h=b43e88ca28085c51127940d9ce0682551be69b61;hb=0bff3f4bb6e2ad90568897c3a233919f9b6bf51a;hp=a46244966250e3a22f10bea3254693dab3ef93ef;hpb=b6090f4d654d4eb195d6729f7e04d9d1440269be;p=binutils-gdb.git diff --git a/bfd/libbfd.c b/bfd/libbfd.c index a4624496625..b43e88ca280 100644 --- a/bfd/libbfd.c +++ b/bfd/libbfd.c @@ -1,5 +1,6 @@ /* Assorted BFD support routines, only used internally. - Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 98, 1999 + Free Software Foundation, Inc. Written by Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -16,149 +17,201 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bfd.h" #include "sysdep.h" #include "libbfd.h" +#ifndef HAVE_GETPAGESIZE +#define getpagesize() 2048 +#endif + +static int real_read PARAMS ((PTR, size_t, size_t, FILE *)); + /* SECTION - libbfd + Internal functions DESCRIPTION - This file contains various routines which are used within BFD. + These routines are used within BFD. They are not intended for export, but are documented here for completeness. */ -boolean -DEFUN(_bfd_dummy_new_section_hook,(ignore, ignore_newsect), - bfd *ignore AND - asection *ignore_newsect) -{ - return true; -} +/* A routine which is used in target vectors for unsupported + operations. */ +/*ARGSUSED*/ boolean -DEFUN(bfd_false ,(ignore), - bfd *ignore) +bfd_false (ignore) + bfd *ignore ATTRIBUTE_UNUSED; { + bfd_set_error (bfd_error_invalid_operation); return false; } +/* A routine which is used in target vectors for supported operations + which do not actually do anything. */ + +/*ARGSUSED*/ boolean -DEFUN(bfd_true,(ignore), - bfd *ignore) +bfd_true (ignore) + bfd *ignore ATTRIBUTE_UNUSED; { return true; } +/* A routine which is used in target vectors for unsupported + operations which return a pointer value. */ + +/*ARGSUSED*/ PTR -DEFUN(bfd_nullvoidptr,(ignore), - bfd *ignore) +bfd_nullvoidptr (ignore) + bfd *ignore ATTRIBUTE_UNUSED; { - return (PTR)NULL; + bfd_set_error (bfd_error_invalid_operation); + return NULL; } +/*ARGSUSED*/ int -DEFUN(bfd_0,(ignore), - bfd *ignore) +bfd_0 (ignore) + bfd *ignore ATTRIBUTE_UNUSED; { return 0; } +/*ARGSUSED*/ unsigned int -DEFUN(bfd_0u,(ignore), - bfd *ignore) +bfd_0u (ignore) + bfd *ignore ATTRIBUTE_UNUSED; { return 0; } +/*ARGUSED*/ +long +bfd_0l (ignore) + bfd *ignore ATTRIBUTE_UNUSED; +{ + return 0; +} + +/* A routine which is used in target vectors for unsupported + operations which return -1 on error. */ + +/*ARGSUSED*/ +long +_bfd_n1 (ignore_abfd) + bfd *ignore_abfd ATTRIBUTE_UNUSED; +{ + bfd_set_error (bfd_error_invalid_operation); + return -1; +} + +/*ARGSUSED*/ void -DEFUN(bfd_void,(ignore), - bfd *ignore) +bfd_void (ignore) + bfd *ignore ATTRIBUTE_UNUSED; { } +/*ARGSUSED*/ boolean -DEFUN(_bfd_dummy_core_file_matches_executable_p,(ignore_core_bfd, ignore_exec_bfd), - bfd *ignore_core_bfd AND - bfd *ignore_exec_bfd) +_bfd_nocore_core_file_matches_executable_p (ignore_core_bfd, ignore_exec_bfd) + bfd *ignore_core_bfd ATTRIBUTE_UNUSED; + bfd *ignore_exec_bfd ATTRIBUTE_UNUSED; { - bfd_error = invalid_operation; + bfd_set_error (bfd_error_invalid_operation); return false; } -/* of course you can't initialize a function to be the same as another, grr */ +/* Routine to handle core_file_failing_command entry point for targets + without core file support. */ +/*ARGSUSED*/ char * -DEFUN(_bfd_dummy_core_file_failing_command,(ignore_abfd), - bfd *ignore_abfd) +_bfd_nocore_core_file_failing_command (ignore_abfd) + bfd *ignore_abfd ATTRIBUTE_UNUSED; { + bfd_set_error (bfd_error_invalid_operation); return (char *)NULL; } +/* Routine to handle core_file_failing_signal entry point for targets + without core file support. */ + +/*ARGSUSED*/ int -DEFUN(_bfd_dummy_core_file_failing_signal,(ignore_abfd), - bfd *ignore_abfd) +_bfd_nocore_core_file_failing_signal (ignore_abfd) + bfd *ignore_abfd ATTRIBUTE_UNUSED; { + bfd_set_error (bfd_error_invalid_operation); return 0; } -bfd_target * -DEFUN(_bfd_dummy_target,(ignore_abfd), - bfd *ignore_abfd) +/*ARGSUSED*/ +const bfd_target * +_bfd_dummy_target (ignore_abfd) + bfd *ignore_abfd ATTRIBUTE_UNUSED; { + bfd_set_error (bfd_error_wrong_format); return 0; } -/** zalloc -- allocate and clear storage */ +/* Allocate memory using malloc. */ - -#ifndef zalloc -char * -DEFUN(zalloc,(size), - bfd_size_type size) +PTR +bfd_malloc (size) + size_t size; { - char *ptr = (char *) malloc ((int)size); - - if ((ptr != NULL) && (size != 0)) - memset(ptr,0, size); + PTR ptr; + ptr = (PTR) malloc (size); + if (ptr == NULL && size != 0) + bfd_set_error (bfd_error_no_memory); return ptr; } -#endif -/* -INTERNAL_FUNCTION - bfd_xmalloc +/* Reallocate memory using realloc. */ -SYNOPSIS - PTR bfd_xmalloc( bfd_size_type size); +PTR +bfd_realloc (ptr, size) + PTR ptr; + size_t size; +{ + PTR ret; -DESCRIPTION - Like malloc, but exit if no more memory. + if (ptr == NULL) + ret = malloc (size); + else + ret = realloc (ptr, size); -*/ + if (ret == NULL) + bfd_set_error (bfd_error_no_memory); -/** There is major inconsistency in how running out of memory is handled. - Some routines return a NULL, and set bfd_error to no_memory. - However, obstack routines can't do this ... */ + return ret; +} +/* Allocate memory using malloc and clear it. */ -DEFUN(PTR bfd_xmalloc,(size), - bfd_size_type size) +PTR +bfd_zmalloc (size) + size_t size; { - static CONST char no_memory_message[] = "Virtual memory exhausted!\n"; PTR ptr; - if (size == 0) size = 1; - ptr = (PTR)malloc(size); - if (!ptr) + + ptr = (PTR) malloc (size); + + if (size != 0) { - write (2, no_memory_message, sizeof(no_memory_message)-1); - exit (-1); + if (ptr == NULL) + bfd_set_error (bfd_error_no_memory); + else + memset (ptr, 0, size); } + return ptr; } @@ -172,43 +225,357 @@ DEFUN(PTR bfd_xmalloc,(size), contents (0 for non-archive elements). For archive entries this is the first octet in the file, NOT the beginning of the archive header. */ -static -int DEFUN(real_read,(where, a,b, file), - PTR where AND - int a AND - int b AND - FILE *file) +static int +real_read (where, a,b, file) + PTR where; + size_t a; + size_t b; + FILE *file; { - return fread(where, a,b,file); + /* FIXME - this looks like an optimization, but it's really to cover + up for a feature of some OSs (not solaris - sigh) that + ld/pe-dll.c takes advantage of (apparently) when it creates BFDs + internally and tries to link against them. BFD seems to be smart + enough to realize there are no symbol records in the "file" that + doesn't exist but attempts to read them anyway. On Solaris, + attempting to read zero bytes from a NULL file results in a core + dump, but on other platforms it just returns zero bytes read. + This makes it to something reasonable. - DJ */ + if (a == 0 || b == 0) + return 0; + +#if defined (__VAX) && defined (VMS) + /* Apparently fread on Vax VMS does not keep the record length + information. */ + return read (fileno (file), where, a * b); +#else + return fread (where, a, b, file); +#endif } + +/* Return value is amount read (FIXME: how are errors and end of file dealt + with? We never call bfd_set_error, which is probably a mistake). */ + bfd_size_type -DEFUN(bfd_read,(ptr, size, nitems, abfd), - PTR ptr AND - bfd_size_type size AND - bfd_size_type nitems AND - bfd *abfd) +bfd_read (ptr, size, nitems, abfd) + PTR ptr; + bfd_size_type size; + bfd_size_type nitems; + bfd *abfd; { int nread; - nread = real_read (ptr, 1, (int)(size*nitems), bfd_cache_lookup(abfd)); -#ifdef FILE_OFFSET_IS_CHAR_INDEX + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + { + struct bfd_in_memory *bim; + bfd_size_type get; + + bim = (struct bfd_in_memory *) abfd->iostream; + get = size * nitems; + if (abfd->where + get > bim->size) + { + get = bim->size - abfd->where; + bfd_set_error (bfd_error_file_truncated); + } + memcpy (ptr, bim->buffer + abfd->where, get); + abfd->where += get; + return get; + } + + nread = real_read (ptr, 1, (size_t)(size*nitems), bfd_cache_lookup(abfd)); if (nread > 0) abfd->where += nread; -#endif + + /* Set bfd_error if we did not read as much data as we expected. + + If the read failed due to an error set the bfd_error_system_call, + else set bfd_error_file_truncated. + + A BFD backend may wish to override bfd_error_file_truncated to + provide something more useful (eg. no_symbols or wrong_format). */ + if (nread != (int) (size * nitems)) + { + if (ferror (bfd_cache_lookup (abfd))) + bfd_set_error (bfd_error_system_call); + else + bfd_set_error (bfd_error_file_truncated); + } + return nread; } +/* The window support stuff should probably be broken out into + another file.... */ +/* The idea behind the next and refcount fields is that one mapped + region can suffice for multiple read-only windows or multiple + non-overlapping read-write windows. It's not implemented yet + though. */ +struct _bfd_window_internal { + struct _bfd_window_internal *next; + PTR data; + bfd_size_type size; + int refcount : 31; /* should be enough... */ + unsigned mapped : 1; /* 1 = mmap, 0 = malloc */ +}; + +void +bfd_init_window (windowp) + bfd_window *windowp; +{ + windowp->data = 0; + windowp->i = 0; + windowp->size = 0; +} + +/* Currently, if USE_MMAP is undefined, none if the window stuff is + used. Okay, so it's mis-named. At least the command-line option + "--without-mmap" is more obvious than "--without-windows" or some + such. */ +#ifdef USE_MMAP + +#undef HAVE_MPROTECT /* code's not tested yet */ + +#if HAVE_MMAP || HAVE_MPROTECT || HAVE_MADVISE +#include +#endif + +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif + +static int debug_windows; + +void +bfd_free_window (windowp) + bfd_window *windowp; +{ + bfd_window_internal *i = windowp->i; + windowp->i = 0; + windowp->data = 0; + if (i == 0) + return; + i->refcount--; + if (debug_windows) + fprintf (stderr, "freeing window @%p<%p,%lx,%p>\n", + windowp, windowp->data, windowp->size, windowp->i); + if (i->refcount != 0) + return; + + if (i->mapped) + { +#ifdef HAVE_MMAP + munmap (i->data, i->size); + goto no_free; +#else + abort (); +#endif + } +#ifdef HAVE_MPROTECT + mprotect (i->data, i->size, PROT_READ | PROT_WRITE); +#endif + free (i->data); +#ifdef HAVE_MMAP + no_free: +#endif + i->data = 0; + /* There should be no more references to i at this point. */ + free (i); +} + +static int ok_to_map = 1; + +boolean +bfd_get_file_window (abfd, offset, size, windowp, writable) + bfd *abfd; + file_ptr offset; + bfd_size_type size; + bfd_window *windowp; + boolean writable; +{ + static size_t pagesize; + bfd_window_internal *i = windowp->i; + size_t size_to_alloc = size; + + if (debug_windows) + fprintf (stderr, "bfd_get_file_window (%p, %6ld, %6ld, %p<%p,%lx,%p>, %d)", + abfd, (long) offset, (long) size, + windowp, windowp->data, (unsigned long) windowp->size, + windowp->i, writable); + + /* Make sure we know the page size, so we can be friendly to mmap. */ + if (pagesize == 0) + pagesize = getpagesize (); + if (pagesize == 0) + abort (); + + if (i == 0) + { + windowp->i = i = (bfd_window_internal *) bfd_zmalloc (sizeof (bfd_window_internal)); + if (i == 0) + return false; + i->data = 0; + } +#ifdef HAVE_MMAP + if (ok_to_map + && (i->data == 0 || i->mapped == 1) + && (abfd->flags & BFD_IN_MEMORY) == 0) + { + file_ptr file_offset, offset2; + size_t real_size; + int fd; + FILE *f; + + /* Find the real file and the real offset into it. */ + while (abfd->my_archive != NULL) + { + offset += abfd->origin; + abfd = abfd->my_archive; + } + f = bfd_cache_lookup (abfd); + fd = fileno (f); + + /* Compute offsets and size for mmap and for the user's data. */ + offset2 = offset % pagesize; + if (offset2 < 0) + abort (); + file_offset = offset - offset2; + real_size = offset + size - file_offset; + real_size = real_size + pagesize - 1; + real_size -= real_size % pagesize; + + /* If we're re-using a memory region, make sure it's big enough. */ + if (i->data && i->size < size) + { + munmap (i->data, i->size); + i->data = 0; + } + i->data = mmap (i->data, real_size, + writable ? PROT_WRITE | PROT_READ : PROT_READ, + (writable + ? MAP_FILE | MAP_PRIVATE + : MAP_FILE | MAP_SHARED), + fd, file_offset); + if (i->data == (PTR) -1) + { + /* An error happened. Report it, or try using malloc, or + something. */ + bfd_set_error (bfd_error_system_call); + i->data = 0; + windowp->data = 0; + if (debug_windows) + fprintf (stderr, "\t\tmmap failed!\n"); + return false; + } + if (debug_windows) + fprintf (stderr, "\n\tmapped %ld at %p, offset is %ld\n", + (long) real_size, i->data, (long) offset2); + i->size = real_size; + windowp->data = (PTR) ((bfd_byte *) i->data + offset2); + windowp->size = size; + i->mapped = 1; + return true; + } + else if (debug_windows) + { + if (ok_to_map) + fprintf (stderr, _("not mapping: data=%lx mapped=%d\n"), + (unsigned long) i->data, (int) i->mapped); + else + fprintf (stderr, _("not mapping: env var not set\n")); + } +#else + ok_to_map = 0; +#endif + +#ifdef HAVE_MPROTECT + if (!writable) + { + size_to_alloc += pagesize - 1; + size_to_alloc -= size_to_alloc % pagesize; + } +#endif + if (debug_windows) + fprintf (stderr, "\n\t%s(%6ld)", + i->data ? "realloc" : " malloc", (long) size_to_alloc); + i->data = (PTR) bfd_realloc (i->data, size_to_alloc); + if (debug_windows) + fprintf (stderr, "\t-> %p\n", i->data); + i->refcount = 1; + if (i->data == NULL) + { + if (size_to_alloc == 0) + return true; + bfd_set_error (bfd_error_no_memory); + return false; + } + if (bfd_seek (abfd, offset, SEEK_SET) != 0) + return false; + i->size = bfd_read (i->data, size, 1, abfd); + if (i->size != size) + return false; + i->mapped = 0; +#ifdef HAVE_MPROTECT + if (!writable) + { + if (debug_windows) + fprintf (stderr, "\tmprotect (%p, %ld, PROT_READ)\n", i->data, + (long) i->size); + mprotect (i->data, i->size, PROT_READ); + } +#endif + windowp->data = i->data; + windowp->size = i->size; + return true; +} + +#endif /* USE_MMAP */ + bfd_size_type -DEFUN(bfd_write,(ptr, size, nitems, abfd), - CONST PTR ptr AND - bfd_size_type size AND - bfd_size_type nitems AND - bfd *abfd) -{ - int nwrote = fwrite (ptr, 1, (int)(size*nitems), bfd_cache_lookup(abfd)); -#ifdef FILE_OFFSET_IS_CHAR_INDEX +bfd_write (ptr, size, nitems, abfd) + CONST PTR ptr; + bfd_size_type size; + bfd_size_type nitems; + bfd *abfd; +{ + long nwrote; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + { + struct bfd_in_memory *bim = (struct bfd_in_memory *) (abfd->iostream); + size *= nitems; + if (abfd->where + size > bim->size) + { + long newsize, oldsize = (bim->size + 127) & ~127; + bim->size = abfd->where + size; + /* Round up to cut down on memory fragmentation */ + newsize = (bim->size + 127) & ~127; + if (newsize > oldsize) + { + bim->buffer = bfd_realloc (bim->buffer, newsize); + if (bim->buffer == 0) + { + bim->size = 0; + return 0; + } + } + } + memcpy (bim->buffer + abfd->where, ptr, size); + abfd->where += size; + return size; + } + + nwrote = fwrite (ptr, 1, (size_t) (size * nitems), + bfd_cache_lookup (abfd)); if (nwrote > 0) abfd->where += nwrote; + if ((bfd_size_type) nwrote != size * nitems) + { +#ifdef ENOSPC + if (nwrote >= 0) + errno = ENOSPC; #endif + bfd_set_error (bfd_error_system_call); + } return nwrote; } @@ -220,27 +587,31 @@ SYNOPSIS void bfd_write_bigendian_4byte_int(bfd *abfd, int i); DESCRIPTION - Writes a 4 byte integer to the outputing bfd, in big endian - mode regardless of what else is going on. This is usefull in + Write a 4 byte integer @var{i} to the output BFD @var{abfd}, in big + endian order regardless of what else is going on. This is useful in archives. */ void -DEFUN(bfd_write_bigendian_4byte_int,(abfd, i), - bfd *abfd AND - int i) +bfd_write_bigendian_4byte_int (abfd, i) + bfd *abfd; + int i; { bfd_byte buffer[4]; - _do_putb32(i, buffer); - bfd_write((PTR)buffer, 4, 1, abfd); + bfd_putb32(i, buffer); + if (bfd_write((PTR)buffer, 4, 1, abfd) != 4) + abort (); } long -DEFUN(bfd_tell,(abfd), - bfd *abfd) +bfd_tell (abfd) + bfd *abfd; { file_ptr ptr; + if ((abfd->flags & BFD_IN_MEMORY) != 0) + return abfd->where; + ptr = ftell (bfd_cache_lookup(abfd)); if (abfd->my_archive) @@ -250,10 +621,47 @@ DEFUN(bfd_tell,(abfd), } int -DEFUN(bfd_seek,(abfd, position, direction), - bfd * CONST abfd AND - CONST file_ptr position AND - CONST int direction) +bfd_flush (abfd) + bfd *abfd; +{ + if ((abfd->flags & BFD_IN_MEMORY) != 0) + return 0; + return fflush (bfd_cache_lookup(abfd)); +} + +/* Returns 0 for success, negative value for failure (in which case + bfd_get_error can retrieve the error code). */ +int +bfd_stat (abfd, statbuf) + bfd *abfd; + struct stat *statbuf; +{ + FILE *f; + int result; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + abort (); + + f = bfd_cache_lookup (abfd); + if (f == NULL) + { + bfd_set_error (bfd_error_system_call); + return -1; + } + result = fstat (fileno (f), statbuf); + if (result < 0) + bfd_set_error (bfd_error_system_call); + return result; +} + +/* Returns 0 for success, nonzero for failure (in which case bfd_get_error + can retrieve the error code). */ + +int +bfd_seek (abfd, position, direction) + bfd *abfd; + file_ptr position; + int direction; { int result; FILE *f; @@ -266,10 +674,19 @@ DEFUN(bfd_seek,(abfd, position, direction), if (direction == SEEK_CUR && position == 0) return 0; -#ifdef FILE_OFFSET_IS_CHAR_INDEX + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + { + if (direction == SEEK_SET) + abfd->where = position; + else + abfd->where += position; + return 0; + } + if (abfd->format != bfd_archive && abfd->my_archive == 0) { -#ifndef NDEBUG +#if 0 /* Explanation for this code: I'm only about 95+% sure that the above conditions are sufficient and that all i/o calls are properly adjusting the `where' field. So this is sort of an `assert' @@ -300,7 +717,6 @@ DEFUN(bfd_seek,(abfd, position, direction), In the meantime, no optimization for archives. */ } -#endif f = bfd_cache_lookup (abfd); file_position = position; @@ -310,74 +726,33 @@ DEFUN(bfd_seek,(abfd, position, direction), result = fseek (f, file_position, direction); if (result != 0) - /* Force redetermination of `where' field. */ - bfd_tell (abfd); + { + int hold_errno = errno; + + /* Force redetermination of `where' field. */ + bfd_tell (abfd); + + /* An EINVAL error probably means that the file offset was + absurd. */ + if (hold_errno == EINVAL) + bfd_set_error (bfd_error_file_truncated); + else + { + bfd_set_error (bfd_error_system_call); + errno = hold_errno; + } + } else { -#ifdef FILE_OFFSET_IS_CHAR_INDEX /* Adjust `where' field. */ if (direction == SEEK_SET) abfd->where = position; else abfd->where += position; -#endif } return result; } -/** Make a string table */ - -/*>bfd.h< - Add string to table pointed to by table, at location starting with free_ptr. - resizes the table if necessary (if it's NULL, creates it, ignoring - table_length). Updates free_ptr, table, table_length */ - -boolean -DEFUN(bfd_add_to_string_table,(table, new_string, table_length, free_ptr), - char **table AND - char *new_string AND - unsigned int *table_length AND - char **free_ptr) -{ - size_t string_length = strlen (new_string) + 1; /* include null here */ - char *base = *table; - size_t space_length = *table_length; - unsigned int offset = (base ? *free_ptr - base : 0); - - if (base == NULL) { - /* Avoid a useless regrow if we can (but of course we still - take it next time */ - space_length = (string_length < DEFAULT_STRING_SPACE_SIZE ? - DEFAULT_STRING_SPACE_SIZE : string_length+1); - base = zalloc (space_length); - - if (base == NULL) { - bfd_error = no_memory; - return false; - } - } - - if ((size_t)(offset + string_length) >= space_length) { - /* Make sure we will have enough space */ - while ((size_t)(offset + string_length) >= space_length) - space_length += space_length/2; /* grow by 50% */ - - base = (char *) realloc (base, space_length); - if (base == NULL) { - bfd_error = no_memory; - return false; - } - - } - - memcpy (base + offset, new_string, string_length); - *table = base; - *table_length = space_length; - *free_ptr = base + offset + string_length; - - return true; -} - /** The do-it-yourself (byte) sex-change kit */ /* The middle letter e.g. getshort indicates Big or Little endian @@ -400,110 +775,237 @@ DESCRIPTION sections; each access (except for bytes) is vectored through the target format of the BFD and mangled accordingly. The mangling performs any necessary endian translations and - removes alignment restrictions. - + removes alignment restrictions. Note that types accepted and + returned by these macros are identical so they can be swapped + around in macros---for example, @file{libaout.h} defines <> + to either <> or <>. + + In the put routines, @var{val} must be a <>. If we are on a + system without prototypes, the caller is responsible for making + sure that is true, with a cast if necessary. We don't cast + them in the macro definitions because that would prevent <> + or <> from detecting sins such as passing a pointer. + To detect calling these with less than a <>, use + <> on a host with 64 bit <>'s. + +. +.{* Byte swapping macros for user section data. *} +. .#define bfd_put_8(abfd, val, ptr) \ -. (*((char *)ptr) = (char)val) +. ((void) (*((unsigned char *)(ptr)) = (unsigned char)(val))) +.#define bfd_put_signed_8 \ +. bfd_put_8 .#define bfd_get_8(abfd, ptr) \ -. (*((char *)ptr)) +. (*(unsigned char *)(ptr)) +.#define bfd_get_signed_8(abfd, ptr) \ +. ((*(unsigned char *)(ptr) ^ 0x80) - 0x80) +. .#define bfd_put_16(abfd, val, ptr) \ -. BFD_SEND(abfd, bfd_putx16, (val,ptr)) +. BFD_SEND(abfd, bfd_putx16, ((val),(ptr))) +.#define bfd_put_signed_16 \ +. bfd_put_16 .#define bfd_get_16(abfd, ptr) \ . BFD_SEND(abfd, bfd_getx16, (ptr)) +.#define bfd_get_signed_16(abfd, ptr) \ +. BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) +. .#define bfd_put_32(abfd, val, ptr) \ -. BFD_SEND(abfd, bfd_putx32, (val,ptr)) +. BFD_SEND(abfd, bfd_putx32, ((val),(ptr))) +.#define bfd_put_signed_32 \ +. bfd_put_32 .#define bfd_get_32(abfd, ptr) \ . BFD_SEND(abfd, bfd_getx32, (ptr)) +.#define bfd_get_signed_32(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx_signed_32, (ptr)) +. .#define bfd_put_64(abfd, val, ptr) \ -. BFD_SEND(abfd, bfd_putx64, (val, ptr)) +. BFD_SEND(abfd, bfd_putx64, ((val), (ptr))) +.#define bfd_put_signed_64 \ +. bfd_put_64 .#define bfd_get_64(abfd, ptr) \ . BFD_SEND(abfd, bfd_getx64, (ptr)) - +.#define bfd_get_signed_64(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx_signed_64, (ptr)) +. +.#define bfd_get(bits, abfd, ptr) \ +. ((bits) == 8 ? bfd_get_8 (abfd, ptr) \ +. : (bits) == 16 ? bfd_get_16 (abfd, ptr) \ +. : (bits) == 32 ? bfd_get_32 (abfd, ptr) \ +. : (bits) == 64 ? bfd_get_64 (abfd, ptr) \ +. : (abort (), (bfd_vma) - 1)) +. +.#define bfd_put(bits, abfd, val, ptr) \ +. ((bits) == 8 ? bfd_put_8 (abfd, val, ptr) \ +. : (bits) == 16 ? bfd_put_16 (abfd, val, ptr) \ +. : (bits) == 32 ? bfd_put_32 (abfd, val, ptr) \ +. : (bits) == 64 ? bfd_put_64 (abfd, val, ptr) \ +. : (abort (), (void) 0)) +. */ /* FUNCTION bfd_h_put_size -FUNCTION bfd_h_get_size DESCRIPTION These macros have the same function as their <> - bretherin, except that they are used for removing information + bretheren, except that they are used for removing information for the header records of object files. Believe it or not, some object files keep their header records in big endian - order, and their data in little endan order. - + order and their data in little endian order. +. +.{* Byte swapping macros for file header data. *} +. .#define bfd_h_put_8(abfd, val, ptr) \ -. (*((char *)ptr) = (char)val) +. bfd_put_8 (abfd, val, ptr) +.#define bfd_h_put_signed_8(abfd, val, ptr) \ +. bfd_put_8 (abfd, val, ptr) .#define bfd_h_get_8(abfd, ptr) \ -. (*((char *)ptr)) +. bfd_get_8 (abfd, ptr) +.#define bfd_h_get_signed_8(abfd, ptr) \ +. bfd_get_signed_8 (abfd, ptr) +. .#define bfd_h_put_16(abfd, val, ptr) \ . BFD_SEND(abfd, bfd_h_putx16,(val,ptr)) +.#define bfd_h_put_signed_16 \ +. bfd_h_put_16 .#define bfd_h_get_16(abfd, ptr) \ . BFD_SEND(abfd, bfd_h_getx16,(ptr)) +.#define bfd_h_get_signed_16(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx_signed_16, (ptr)) +. .#define bfd_h_put_32(abfd, val, ptr) \ . BFD_SEND(abfd, bfd_h_putx32,(val,ptr)) +.#define bfd_h_put_signed_32 \ +. bfd_h_put_32 .#define bfd_h_get_32(abfd, ptr) \ . BFD_SEND(abfd, bfd_h_getx32,(ptr)) +.#define bfd_h_get_signed_32(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx_signed_32, (ptr)) +. .#define bfd_h_put_64(abfd, val, ptr) \ . BFD_SEND(abfd, bfd_h_putx64,(val, ptr)) +.#define bfd_h_put_signed_64 \ +. bfd_h_put_64 .#define bfd_h_get_64(abfd, ptr) \ . BFD_SEND(abfd, bfd_h_getx64,(ptr)) - +.#define bfd_h_get_signed_64(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx_signed_64, (ptr)) +. */ +/* Sign extension to bfd_signed_vma. */ +#define COERCE16(x) (((bfd_signed_vma) (x) ^ 0x8000) - 0x8000) +#define COERCE32(x) \ + ((bfd_signed_vma) (long) (((unsigned long) (x) ^ 0x80000000) - 0x80000000)) +#define EIGHT_GAZILLION (((BFD_HOST_64_BIT)0x80000000) << 32) +#define COERCE64(x) \ + (((bfd_signed_vma) (x) ^ EIGHT_GAZILLION) - EIGHT_GAZILLION) + bfd_vma -DEFUN(_do_getb16,(addr), - register bfd_byte *addr) +bfd_getb16 (addr) + register const bfd_byte *addr; { - return (addr[0] << 8) | addr[1]; + return (addr[0] << 8) | addr[1]; } bfd_vma -DEFUN(_do_getl16,(addr), - register bfd_byte *addr) +bfd_getl16 (addr) + register const bfd_byte *addr; { - return (addr[1] << 8) | addr[0]; + return (addr[1] << 8) | addr[0]; +} + +bfd_signed_vma +bfd_getb_signed_16 (addr) + register const bfd_byte *addr; +{ + return COERCE16((addr[0] << 8) | addr[1]); +} + +bfd_signed_vma +bfd_getl_signed_16 (addr) + register const bfd_byte *addr; +{ + return COERCE16((addr[1] << 8) | addr[0]); } void -DEFUN(_do_putb16,(data, addr), - bfd_vma data AND - register bfd_byte *addr) +bfd_putb16 (data, addr) + bfd_vma data; + register bfd_byte *addr; { - addr[0] = (bfd_byte)(data >> 8); - addr[1] = (bfd_byte )data; + addr[0] = (bfd_byte)(data >> 8); + addr[1] = (bfd_byte )data; } void -DEFUN(_do_putl16,(data, addr), - bfd_vma data AND - register bfd_byte *addr) +bfd_putl16 (data, addr) + bfd_vma data; + register bfd_byte *addr; { - addr[0] = (bfd_byte )data; - addr[1] = (bfd_byte)(data >> 8); + addr[0] = (bfd_byte )data; + addr[1] = (bfd_byte)(data >> 8); } bfd_vma -DEFUN(_do_getb32,(addr), - register bfd_byte *addr) +bfd_getb32 (addr) + register const bfd_byte *addr; { - return ((((addr[0] << 8) | addr[1]) << 8) | addr[2]) << 8 | addr[3]; + unsigned long v; + + v = (unsigned long) addr[0] << 24; + v |= (unsigned long) addr[1] << 16; + v |= (unsigned long) addr[2] << 8; + v |= (unsigned long) addr[3]; + return (bfd_vma) v; } bfd_vma -_do_getl32 (addr) - register bfd_byte *addr; +bfd_getl32 (addr) + register const bfd_byte *addr; { - return ((((addr[3] << 8) | addr[2]) << 8) | addr[1]) << 8 | addr[0]; + unsigned long v; + + v = (unsigned long) addr[0]; + v |= (unsigned long) addr[1] << 8; + v |= (unsigned long) addr[2] << 16; + v |= (unsigned long) addr[3] << 24; + return (bfd_vma) v; +} + +bfd_signed_vma +bfd_getb_signed_32 (addr) + register const bfd_byte *addr; +{ + unsigned long v; + + v = (unsigned long) addr[0] << 24; + v |= (unsigned long) addr[1] << 16; + v |= (unsigned long) addr[2] << 8; + v |= (unsigned long) addr[3]; + return COERCE32 (v); +} + +bfd_signed_vma +bfd_getl_signed_32 (addr) + register const bfd_byte *addr; +{ + unsigned long v; + + v = (unsigned long) addr[0]; + v |= (unsigned long) addr[1] << 8; + v |= (unsigned long) addr[2] << 16; + v |= (unsigned long) addr[3] << 24; + return COERCE32 (v); } bfd_vma -DEFUN(_do_getb64,(addr), - register bfd_byte *addr) +bfd_getb64 (addr) + register const bfd_byte *addr ATTRIBUTE_UNUSED; { -#ifdef HOST_64_BIT +#ifdef BFD64 bfd_vma low, high; high= ((((((((addr[0]) << 8) | @@ -511,7 +1013,7 @@ DEFUN(_do_getb64,(addr), addr[2]) << 8) | addr[3]) ); - low = ((((((((addr[4]) << 8) | + low = (((((((((bfd_vma)addr[4]) << 8) | addr[5]) << 8) | addr[6]) << 8) | addr[7])); @@ -521,22 +1023,20 @@ DEFUN(_do_getb64,(addr), BFD_FAIL(); return 0; #endif - } bfd_vma -DEFUN(_do_getl64,(addr), - register bfd_byte *addr) +bfd_getl64 (addr) + register const bfd_byte *addr ATTRIBUTE_UNUSED; { - -#ifdef HOST_64_BIT +#ifdef BFD64 bfd_vma low, high; high= (((((((addr[7] << 8) | addr[6]) << 8) | addr[5]) << 8) | addr[4])); - low = (((((((addr[3] << 8) | + low = ((((((((bfd_vma)addr[3] << 8) | addr[2]) << 8) | addr[1]) << 8) | addr[0]) ); @@ -549,10 +1049,57 @@ DEFUN(_do_getl64,(addr), } +bfd_signed_vma +bfd_getb_signed_64 (addr) + register const bfd_byte *addr ATTRIBUTE_UNUSED; +{ +#ifdef BFD64 + bfd_vma low, high; + + high= ((((((((addr[0]) << 8) | + addr[1]) << 8) | + addr[2]) << 8) | + addr[3]) ); + + low = (((((((((bfd_vma)addr[4]) << 8) | + addr[5]) << 8) | + addr[6]) << 8) | + addr[7])); + + return COERCE64(high << 32 | low); +#else + BFD_FAIL(); + return 0; +#endif +} + +bfd_signed_vma +bfd_getl_signed_64 (addr) + register const bfd_byte *addr ATTRIBUTE_UNUSED; +{ +#ifdef BFD64 + bfd_vma low, high; + high= (((((((addr[7] << 8) | + addr[6]) << 8) | + addr[5]) << 8) | + addr[4])); + + low = ((((((((bfd_vma)addr[3] << 8) | + addr[2]) << 8) | + addr[1]) << 8) | + addr[0]) ); + + return COERCE64(high << 32 | low); +#else + BFD_FAIL(); + return 0; +#endif +} + void -DEFUN(_do_putb32,(data, addr), - bfd_vma data AND - register bfd_byte *addr) +bfd_putb32 (data, addr) + bfd_vma data; + register bfd_byte *addr; { addr[0] = (bfd_byte)(data >> 24); addr[1] = (bfd_byte)(data >> 16); @@ -561,21 +1108,22 @@ DEFUN(_do_putb32,(data, addr), } void -DEFUN(_do_putl32,(data, addr), - bfd_vma data AND - register bfd_byte *addr) +bfd_putl32 (data, addr) + bfd_vma data; + register bfd_byte *addr; { addr[0] = (bfd_byte)data; addr[1] = (bfd_byte)(data >> 8); addr[2] = (bfd_byte)(data >> 16); addr[3] = (bfd_byte)(data >> 24); } + void -DEFUN(_do_putb64,(data, addr), - bfd_vma data AND - register bfd_byte *addr) +bfd_putb64 (data, addr) + bfd_vma data ATTRIBUTE_UNUSED; + register bfd_byte *addr ATTRIBUTE_UNUSED; { -#ifdef HOST_64_BIT +#ifdef BFD64 addr[0] = (bfd_byte)(data >> (7*8)); addr[1] = (bfd_byte)(data >> (6*8)); addr[2] = (bfd_byte)(data >> (5*8)); @@ -587,15 +1135,14 @@ DEFUN(_do_putb64,(data, addr), #else BFD_FAIL(); #endif - } void -DEFUN(_do_putl64,(data, addr), - bfd_vma data AND - register bfd_byte *addr) +bfd_putl64 (data, addr) + bfd_vma data ATTRIBUTE_UNUSED; + register bfd_byte *addr ATTRIBUTE_UNUSED; { -#ifdef HOST_64_BIT +#ifdef BFD64 addr[7] = (bfd_byte)(data >> (7*8)); addr[6] = (bfd_byte)(data >> (6*8)); addr[5] = (bfd_byte)(data >> (5*8)); @@ -607,27 +1154,77 @@ DEFUN(_do_putl64,(data, addr), #else BFD_FAIL(); #endif - } - /* Default implementation */ boolean -DEFUN(bfd_generic_get_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) -{ - if (count == 0) - return true; - if ((bfd_size_type)(offset+count) > section->_raw_size - || bfd_seek(abfd, (file_ptr)(section->filepos + offset), SEEK_SET) == -1 - || bfd_read(location, (bfd_size_type)1, count, abfd) != count) - return (false); /* on error */ - return (true); +_bfd_generic_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (count == 0) + return true; + + if ((bfd_size_type) (offset + count) > section->_raw_size) + { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0 + || bfd_read (location, (bfd_size_type) 1, count, abfd) != count) + return false; + + return true; +} + +boolean +_bfd_generic_get_section_contents_in_window (abfd, section, w, offset, count) + bfd *abfd ATTRIBUTE_UNUSED; + sec_ptr section ATTRIBUTE_UNUSED; + bfd_window *w ATTRIBUTE_UNUSED; + file_ptr offset ATTRIBUTE_UNUSED; + bfd_size_type count ATTRIBUTE_UNUSED; +{ +#ifdef USE_MMAP + if (count == 0) + return true; + if (abfd->xvec->_bfd_get_section_contents != _bfd_generic_get_section_contents) + { + /* We don't know what changes the bfd's get_section_contents + method may have to make. So punt trying to map the file + window, and let get_section_contents do its thing. */ + /* @@ FIXME : If the internal window has a refcount of 1 and was + allocated with malloc instead of mmap, just reuse it. */ + bfd_free_window (w); + w->i = (bfd_window_internal *) bfd_zmalloc (sizeof (bfd_window_internal)); + if (w->i == NULL) + return false; + w->i->data = (PTR) bfd_malloc ((size_t) count); + if (w->i->data == NULL) + { + free (w->i); + w->i = NULL; + return false; + } + w->i->mapped = 0; + w->i->refcount = 1; + w->size = w->i->size = count; + w->data = w->i->data; + return bfd_get_section_contents (abfd, section, w->data, offset, count); + } + if ((bfd_size_type) (offset+count) > section->_raw_size + || (bfd_get_file_window (abfd, section->filepos + offset, count, w, true) + == false)) + return false; + return true; +#else + abort (); +#endif } /* This generic function can only be used in implementations where creating @@ -635,39 +1232,76 @@ DEFUN(bfd_generic_get_section_contents, (abfd, section, location, offset, count) in read-write files, though. See other set_section_contents functions to see why it doesn't work for new sections. */ boolean -DEFUN(bfd_generic_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) -{ - if (count == 0) - return true; - if ((bfd_size_type)(offset+count) > bfd_get_section_size_after_reloc(section) - || bfd_seek(abfd, (file_ptr)(section->filepos + offset), SEEK_SET) == -1 - || bfd_write(location, (bfd_size_type)1, count, abfd) != count) - return (false); /* on error */ - return (true); +_bfd_generic_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (count == 0) + return true; + + if (bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET) == -1 + || bfd_write (location, (bfd_size_type) 1, count, abfd) != count) + return false; + + return true; } /* INTERNAL_FUNCTION bfd_log2 -DESCRIPTION - Return the log base 2 of the value supplied, rounded up. eg an - arg of 1025 would return 11. - SYNOPSIS - bfd_vma bfd_log2(bfd_vma x); + unsigned int bfd_log2(bfd_vma x); + +DESCRIPTION + Return the log base 2 of the value supplied, rounded up. E.g., an + @var{x} of 1025 returns 11. */ -bfd_vma bfd_log2(x) -bfd_vma x; +unsigned int +bfd_log2 (x) + bfd_vma x; { - bfd_vma result = 0; - while ( (bfd_vma)(1<< result) < x) - result++; + unsigned int result = 0; + + while ((x = (x >> 1)) != 0) + ++result; return result; } + +boolean +bfd_generic_is_local_label_name (abfd, name) + bfd *abfd; + const char *name; +{ + char locals_prefix = (bfd_get_symbol_leading_char (abfd) == '_') ? 'L' : '.'; + + return (name[0] == locals_prefix); +} + +/* Can be used from / for bfd_merge_private_bfd_data to check that + endianness matches between input and output file. Returns + true for a match, otherwise returns false and emits an error. */ +boolean +_bfd_generic_verify_endian_match (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + if (ibfd->xvec->byteorder != obfd->xvec->byteorder + && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN) + { + (*_bfd_error_handler) + ("%s: compiled for a %s endian system and target is %s endian", + bfd_get_filename (ibfd), + bfd_big_endian (ibfd) ? "big" : "little", + bfd_big_endian (obfd) ? "big" : "little"); + + bfd_set_error (bfd_error_wrong_format); + return false; + } + + return true; +}