/* Assorted BFD support routines, only used internally.
- Copyright 1990, 91, 92, 93, 94 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.
#include "sysdep.h"
#include "libbfd.h"
+#ifndef HAVE_GETPAGESIZE
+#define getpagesize() 2048
+#endif
+
static int real_read PARAMS ((PTR, size_t, size_t, FILE *));
/*
/*ARGSUSED*/
boolean
bfd_false (ignore)
- bfd *ignore;
+ bfd *ignore ATTRIBUTE_UNUSED;
{
bfd_set_error (bfd_error_invalid_operation);
return false;
/*ARGSUSED*/
boolean
bfd_true (ignore)
- bfd *ignore;
+ bfd *ignore ATTRIBUTE_UNUSED;
{
return true;
}
/*ARGSUSED*/
PTR
bfd_nullvoidptr (ignore)
- bfd *ignore;
+ bfd *ignore ATTRIBUTE_UNUSED;
{
bfd_set_error (bfd_error_invalid_operation);
return NULL;
/*ARGSUSED*/
int
bfd_0 (ignore)
- bfd *ignore;
+ bfd *ignore ATTRIBUTE_UNUSED;
{
return 0;
}
/*ARGSUSED*/
unsigned int
bfd_0u (ignore)
- bfd *ignore;
+ bfd *ignore ATTRIBUTE_UNUSED;
{
return 0;
}
/*ARGUSED*/
long
bfd_0l (ignore)
- bfd *ignore;
+ bfd *ignore ATTRIBUTE_UNUSED;
{
return 0;
}
/*ARGSUSED*/
long
_bfd_n1 (ignore_abfd)
- bfd *ignore_abfd;
+ bfd *ignore_abfd ATTRIBUTE_UNUSED;
{
bfd_set_error (bfd_error_invalid_operation);
return -1;
/*ARGSUSED*/
void
bfd_void (ignore)
- bfd *ignore;
+ bfd *ignore ATTRIBUTE_UNUSED;
{
}
/*ARGSUSED*/
boolean
_bfd_nocore_core_file_matches_executable_p (ignore_core_bfd, ignore_exec_bfd)
- bfd *ignore_core_bfd;
- bfd *ignore_exec_bfd;
+ bfd *ignore_core_bfd ATTRIBUTE_UNUSED;
+ bfd *ignore_exec_bfd ATTRIBUTE_UNUSED;
{
bfd_set_error (bfd_error_invalid_operation);
return false;
/*ARGSUSED*/
char *
_bfd_nocore_core_file_failing_command (ignore_abfd)
- bfd *ignore_abfd;
+ bfd *ignore_abfd ATTRIBUTE_UNUSED;
{
bfd_set_error (bfd_error_invalid_operation);
return (char *)NULL;
/*ARGSUSED*/
int
_bfd_nocore_core_file_failing_signal (ignore_abfd)
- bfd *ignore_abfd;
+ bfd *ignore_abfd ATTRIBUTE_UNUSED;
{
bfd_set_error (bfd_error_invalid_operation);
return 0;
/*ARGSUSED*/
const bfd_target *
_bfd_dummy_target (ignore_abfd)
- bfd *ignore_abfd;
+ bfd *ignore_abfd ATTRIBUTE_UNUSED;
{
bfd_set_error (bfd_error_wrong_format);
return 0;
}
\f
+/* Allocate memory using malloc. */
+
+PTR
+bfd_malloc (size)
+ size_t size;
+{
+ PTR ptr;
-#ifndef bfd_zmalloc
-/* allocate and clear storage */
+ ptr = (PTR) malloc (size);
+ if (ptr == NULL && size != 0)
+ bfd_set_error (bfd_error_no_memory);
+ return ptr;
+}
-char *
+/* Reallocate memory using realloc. */
+
+PTR
+bfd_realloc (ptr, size)
+ PTR ptr;
+ size_t size;
+{
+ PTR ret;
+
+ if (ptr == NULL)
+ ret = malloc (size);
+ else
+ ret = realloc (ptr, size);
+
+ if (ret == NULL)
+ bfd_set_error (bfd_error_no_memory);
+
+ return ret;
+}
+
+/* Allocate memory using malloc and clear it. */
+
+PTR
bfd_zmalloc (size)
- bfd_size_type size;
+ size_t size;
{
- char *ptr = (char *) malloc ((size_t) size);
+ PTR ptr;
+
+ ptr = (PTR) malloc (size);
- if (ptr && size)
- memset(ptr, 0, (size_t) size);
+ if (size != 0)
+ {
+ if (ptr == NULL)
+ bfd_set_error (bfd_error_no_memory);
+ else
+ memset (ptr, 0, size);
+ }
return ptr;
}
-#endif /* bfd_zmalloc */
\f
/* Some IO code */
size_t b;
FILE *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
bfd *abfd;
{
int nread;
+
+ 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)
+ {
+ if (bim->size < (bfd_size_type) abfd->where)
+ get = 0;
+ else
+ 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));
-#ifdef FILE_OFFSET_IS_CHAR_INDEX
if (nread > 0)
abfd->where += nread;
-#endif
/* Set bfd_error if we did not read as much data as we expected.
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 (nread != (int) (size * nitems))
{
if (ferror (bfd_cache_lookup (abfd)))
bfd_set_error (bfd_error_system_call);
windowp->i = 0;
windowp->size = 0;
}
+\f
+/* 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
-#include <sys/types.h>
+#if HAVE_MMAP || HAVE_MPROTECT || HAVE_MADVISE
#include <sys/mman.h>
#endif
file_ptr offset;
bfd_size_type size;
bfd_window *windowp;
- int writable;
+ boolean writable;
{
static size_t pagesize;
bfd_window_internal *i = windowp->i;
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, windowp->size, windowp->i,
- writable);
+ 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)
i->data = 0;
}
#ifdef HAVE_MMAP
- if (ok_to_map && (i->data == 0 || i->mapped == 1))
+ 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;
}
i->data = mmap (i->data, real_size,
writable ? PROT_WRITE | PROT_READ : PROT_READ,
- writable ? MAP_FILE | MAP_PRIVATE : MAP_FILE,
+ (writable
+ ? MAP_FILE | MAP_PRIVATE
+ : MAP_FILE | MAP_SHARED),
fd, file_offset);
if (i->data == (PTR) -1)
{
fprintf (stderr, "\n\tmapped %ld at %p, offset is %ld\n",
(long) real_size, i->data, (long) offset2);
i->size = real_size;
- windowp->data = i->data + offset2;
+ 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=%x mapped=%d\n",
- i->data, i->mapped);
+ 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");
+ fprintf (stderr, _("not mapping: env var not set\n"));
}
#else
ok_to_map = 0;
if (debug_windows)
fprintf (stderr, "\n\t%s(%6ld)",
i->data ? "realloc" : " malloc", (long) size_to_alloc);
- if (i->data)
- i->data = (PTR) realloc (i->data, size_to_alloc);
- else
- i->data = (PTR) malloc (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;
return true;
}
+#endif /* USE_MMAP */
+\f
bfd_size_type
bfd_write (ptr, size, nitems, abfd)
CONST PTR ptr;
bfd_size_type nitems;
bfd *abfd;
{
- long nwrote = fwrite (ptr, 1, (size_t) (size * nitems),
- bfd_cache_lookup (abfd));
-#ifdef FILE_OFFSET_IS_CHAR_INDEX
+ 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;
-#endif
if ((bfd_size_type) nwrote != size * nitems)
{
#ifdef ENOSPC
{
file_ptr ptr;
+ if ((abfd->flags & BFD_IN_MEMORY) != 0)
+ return abfd->where;
+
ptr = ftell (bfd_cache_lookup(abfd));
if (abfd->my_archive)
bfd_flush (abfd)
bfd *abfd;
{
+ if ((abfd->flags & BFD_IN_MEMORY) != 0)
+ return 0;
return fflush (bfd_cache_lookup(abfd));
}
{
FILE *f;
int result;
+
+ if ((abfd->flags & BFD_IN_MEMORY) != 0)
+ abort ();
+
f = bfd_cache_lookup (abfd);
if (f == NULL)
{
if (direction == SEEK_CUR && position == 0)
return 0;
-#ifdef FILE_OFFSET_IS_CHAR_INDEX
+
+ if ((abfd->flags & BFD_IN_MEMORY) != 0)
+ {
+ struct bfd_in_memory *bim;
+
+ bim = (struct bfd_in_memory *) abfd->iostream;
+
+ if (direction == SEEK_SET)
+ abfd->where = position;
+ else
+ abfd->where += position;
+
+ if ((bfd_size_type) abfd->where > bim->size)
+ {
+ if ((abfd->direction == write_direction) ||
+ (abfd->direction == both_direction))
+ {
+ long newsize, oldsize = (bim->size + 127) & ~127;
+ bim->size = abfd->where;
+ /* 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;
+ bfd_set_error (bfd_error_no_memory);
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ abfd->where = bim->size;
+ bfd_set_error (bfd_error_file_truncated);
+ return -1;
+ }
+ }
+ return 0;
+ }
+
if (abfd->format != bfd_archive && abfd->my_archive == 0)
{
#if 0
In the meantime, no optimization for archives. */
}
-#endif
f = bfd_cache_lookup (abfd);
file_position = position;
if (result != 0)
{
+ int hold_errno = errno;
+
/* Force redetermination of `where' field. */
bfd_tell (abfd);
- bfd_set_error (bfd_error_system_call);
+
+ /* 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;
}
.{* Byte swapping macros for user section data. *}
.
.#define bfd_put_8(abfd, val, ptr) \
-. (*((unsigned char *)(ptr)) = (unsigned char)(val))
+. ((void) (*((unsigned char *)(ptr)) = (unsigned char)(val)))
.#define bfd_put_signed_8 \
. bfd_put_8
.#define bfd_get_8(abfd, 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))
+.
*/
/*
/* Sign extension to bfd_signed_vma. */
#define COERCE16(x) (((bfd_signed_vma) (x) ^ 0x8000) - 0x8000)
-#define COERCE32(x) (((bfd_signed_vma) (x) ^ 0x80000000) - 0x80000000)
+#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_getb32 (addr)
register const bfd_byte *addr;
{
- return (((((bfd_vma)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
bfd_getl32 (addr)
register const bfd_byte *addr;
{
- return (((((bfd_vma)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;
{
- return COERCE32((((((bfd_vma)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 COERCE32 (v);
}
bfd_signed_vma
bfd_getl_signed_32 (addr)
register const bfd_byte *addr;
{
- return COERCE32((((((bfd_vma)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 COERCE32 (v);
}
bfd_vma
bfd_getb64 (addr)
- register const bfd_byte *addr;
+ register const bfd_byte *addr ATTRIBUTE_UNUSED;
{
#ifdef BFD64
bfd_vma low, high;
bfd_vma
bfd_getl64 (addr)
- register const bfd_byte *addr;
+ register const bfd_byte *addr ATTRIBUTE_UNUSED;
{
#ifdef BFD64
bfd_vma low, high;
bfd_signed_vma
bfd_getb_signed_64 (addr)
- register const bfd_byte *addr;
+ register const bfd_byte *addr ATTRIBUTE_UNUSED;
{
#ifdef BFD64
bfd_vma low, high;
bfd_signed_vma
bfd_getl_signed_64 (addr)
- register const bfd_byte *addr;
+ register const bfd_byte *addr ATTRIBUTE_UNUSED;
{
#ifdef BFD64
bfd_vma low, high;
void
bfd_putb64 (data, addr)
- bfd_vma data;
- register bfd_byte *addr;
+ bfd_vma data ATTRIBUTE_UNUSED;
+ register bfd_byte *addr ATTRIBUTE_UNUSED;
{
#ifdef BFD64
addr[0] = (bfd_byte)(data >> (7*8));
void
bfd_putl64 (data, addr)
- bfd_vma data;
- register bfd_byte *addr;
+ bfd_vma data ATTRIBUTE_UNUSED;
+ register bfd_byte *addr ATTRIBUTE_UNUSED;
{
#ifdef BFD64
addr[7] = (bfd_byte)(data >> (7*8));
file_ptr offset;
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);
+ 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;
- sec_ptr section;
- bfd_window *w;
- file_ptr offset;
- bfd_size_type 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)
w->i = (bfd_window_internal *) bfd_zmalloc (sizeof (bfd_window_internal));
if (w->i == NULL)
return false;
- w->i->data = (PTR) malloc ((size_t) count);
+ w->i->data = (PTR) bfd_malloc ((size_t) count);
if (w->i->data == NULL)
{
free (w->i);
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, 1)
+ || (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
@var{x} of 1025 returns 11.
*/
-unsigned
-bfd_log2(x)
+unsigned int
+bfd_log2 (x)
bfd_vma x;
{
- unsigned 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 (abfd, sym)
+bfd_generic_is_local_label_name (abfd, name)
bfd *abfd;
- asymbol *sym;
+ const char *name;
{
char locals_prefix = (bfd_get_symbol_leading_char (abfd) == '_') ? 'L' : '.';
- return (sym->name[0] == locals_prefix);
+ 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
+ && ibfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN
+ && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
+ {
+ const char *msg;
+
+ if (bfd_big_endian (ibfd))
+ msg = _("%s: compiled for a big endian system and target is little endian");
+ else
+ msg = _("%s: compiled for a little endian system and target is big endian");
+
+ (*_bfd_error_handler) (msg, bfd_get_filename (ibfd));
+
+ bfd_set_error (bfd_error_wrong_format);
+ return false;
+ }
+
+ return true;
+}