X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=bfd%2Fbfd.c;h=5a23c5d690f406cbd8245cf3345273ff2b83bd18;hb=e98fe4f7b54cbdf29aef9287bbb1bea8801dd05a;hp=dd2d45d2fd88f366faa0d6ccc4c56072863ec177;hpb=fc7233808a1d88db99a5181e1ee0f6865f8f5206;p=binutils-gdb.git diff --git a/bfd/bfd.c b/bfd/bfd.c index dd2d45d2fd8..5a23c5d690f 100644 --- a/bfd/bfd.c +++ b/bfd/bfd.c @@ -1,925 +1,1132 @@ - /* -*- C -*- */ +/* Generic BFD library interface and support routines. + Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. -/*** bfd -- binary file diddling routines by Gumby Wallace of Cygnus Support. - Every definition in this file should be exported and declared - in bfd.c. If you don't want it to be user-visible, put it in - libbfd.c! -*/ - -/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. - -This file is part of BFD, the Binary File Diddler. +This file is part of BFD, the Binary File Descriptor library. -BFD is free software; you can redistribute it and/or modify +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. -BFD is distributed in the hope that it will be useful, +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with BFD; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SECTION + <> + + A BFD has type <>; objects of this type are the + cornerstone of any application using BFD. Using BFD + consists of making references though the BFD and to data in the BFD. + + Here is the structure that defines the type <>. It + contains the major data about the file and pointers + to the rest of the data. + +CODE_FRAGMENT +. +.struct _bfd +.{ +. {* The filename the application opened the BFD with. *} +. CONST char *filename; +. +. {* A pointer to the target jump table. *} +. const struct bfd_target *xvec; +. +. {* To avoid dragging too many header files into every file that +. includes `<>', IOSTREAM has been declared as a "char +. *", and MTIME as a "long". Their correct types, to which they +. are cast when used, are "FILE *" and "time_t". The iostream +. is the result of an fopen on the filename. However, if the +. BFD_IN_MEMORY flag is set, then iostream is actually a pointer +. to a bfd_in_memory struct. *} +. PTR iostream; +. +. {* Is the file descriptor being cached? That is, can it be closed as +. needed, and re-opened when accessed later? *} +. +. boolean cacheable; +. +. {* Marks whether there was a default target specified when the +. BFD was opened. This is used to select which matching algorithm +. to use to choose the back end. *} +. +. boolean target_defaulted; +. +. {* The caching routines use these to maintain a +. least-recently-used list of BFDs *} +. +. struct _bfd *lru_prev, *lru_next; +. +. {* When a file is closed by the caching routines, BFD retains +. state information on the file here: *} +. +. file_ptr where; +. +. {* and here: (``once'' means at least once) *} +. +. boolean opened_once; +. +. {* Set if we have a locally maintained mtime value, rather than +. getting it from the file each time: *} +. +. boolean mtime_set; +. +. {* File modified time, if mtime_set is true: *} +. +. long mtime; +. +. {* Reserved for an unimplemented file locking extension.*} +. +. int ifd; +. +. {* The format which belongs to the BFD. (object, core, etc.) *} +. +. bfd_format format; +. +. {* The direction the BFD was opened with*} +. +. enum bfd_direction {no_direction = 0, +. read_direction = 1, +. write_direction = 2, +. both_direction = 3} direction; +. +. {* Format_specific flags*} +. +. flagword flags; +. +. {* Currently my_archive is tested before adding origin to +. anything. I believe that this can become always an add of +. origin, with origin set to 0 for non archive files. *} +. +. file_ptr origin; +. +. {* Remember when output has begun, to stop strange things +. from happening. *} +. boolean output_has_begun; +. +. {* Pointer to linked list of sections*} +. struct sec *sections; +. +. {* The number of sections *} +. unsigned int section_count; +. +. {* Stuff only useful for object files: +. The start address. *} +. bfd_vma start_address; +. +. {* Used for input and output*} +. unsigned int symcount; +. +. {* Symbol table for output BFD (with symcount entries) *} +. struct symbol_cache_entry **outsymbols; +. +. {* Pointer to structure which contains architecture information*} +. const struct bfd_arch_info *arch_info; +. +. {* Stuff only useful for archives:*} +. PTR arelt_data; +. struct _bfd *my_archive; {* The containing archive BFD. *} +. struct _bfd *next; {* The next BFD in the archive. *} +. struct _bfd *archive_head; {* The first BFD in the archive. *} +. boolean has_armap; +. +. {* A chain of BFD structures involved in a link. *} +. struct _bfd *link_next; +. +. {* A field used by _bfd_generic_link_add_archive_symbols. This will +. be used only for archive elements. *} +. int archive_pass; +. +. {* Used by the back end to hold private data. *} +. +. union +. { +. struct aout_data_struct *aout_data; +. struct artdata *aout_ar_data; +. struct _oasys_data *oasys_obj_data; +. struct _oasys_ar_data *oasys_ar_data; +. struct coff_tdata *coff_obj_data; +. struct pe_tdata *pe_obj_data; +. struct xcoff_tdata *xcoff_obj_data; +. struct ecoff_tdata *ecoff_obj_data; +. struct ieee_data_struct *ieee_data; +. struct ieee_ar_data_struct *ieee_ar_data; +. struct srec_data_struct *srec_data; +. struct ihex_data_struct *ihex_data; +. struct tekhex_data_struct *tekhex_data; +. struct elf_obj_tdata *elf_obj_data; +. struct nlm_obj_tdata *nlm_obj_data; +. struct bout_data_struct *bout_data; +. struct sun_core_struct *sun_core_data; +. struct trad_core_struct *trad_core_data; +. struct som_data_struct *som_data; +. struct hpux_core_struct *hpux_core_data; +. struct hppabsd_core_struct *hppabsd_core_data; +. struct sgi_core_struct *sgi_core_data; +. struct lynx_core_struct *lynx_core_data; +. struct osf_core_struct *osf_core_data; +. struct cisco_core_struct *cisco_core_data; +. struct versados_data_struct *versados_data; +. struct netbsd_core_struct *netbsd_core_data; +. PTR any; +. } tdata; +. +. {* Used by the application to hold private data*} +. PTR usrdata; +. +. {* Where all the allocated stuff under this BFD goes *} +. struct obstack memory; +.}; +. +*/ -/* $Id$ */ -#include "sysdep.h" #include "bfd.h" +#include "sysdep.h" + +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif + +#include "bfdlink.h" #include "libbfd.h" +#include "coff/internal.h" +#include "coff/sym.h" +#include "libcoff.h" +#include "libecoff.h" +#undef obj_symbols +#include "elf-bfd.h" + +#include + +/* provide storage for subsystem, stack and heap data which may have been + passed in on the command line. Ld puts this data into a bfd_link_info + struct which ultimately gets passed in to the bfd. When it arrives, copy + it to the following struct so that the data will be available in coffcode.h + where it is needed. The typedef's used are defined in bfd.h */ + -short _bfd_host_big_endian = 0x0100; - /* Accessing the above as (*(char*)&_bfd_host_big_endian), will - return 1 if the host is big-endian, 0 otherwise. - (assuming that a short is two bytes long!!! FIXME) - (See HOST_IS_BIG_ENDIAN_P in bfd.h.) */ -/** Error handling - o - Most functions return nonzero on success (check doc for - precise semantics); 0 or NULL on error. - o - Internal errors are documented by the value of bfd_error. - If that is system_call_error then check errno. - o - The easiest way to report this to the user is to use bfd_perror. +/* +SECTION + Error reporting + + Most BFD functions return nonzero on success (check their + individual documentation for precise semantics). On an error, + they call <> to set an error condition that callers + can check by calling <>. + If that returns <>, then check + <>. + + The easiest way to report a BFD error to the user is to + use <>. + +SUBSECTION + Type <> + + The values returned by <> are defined by the + enumerated type <>. + +CODE_FRAGMENT +. +.typedef enum bfd_error +.{ +. bfd_error_no_error = 0, +. bfd_error_system_call, +. bfd_error_invalid_target, +. bfd_error_wrong_format, +. bfd_error_invalid_operation, +. bfd_error_no_memory, +. bfd_error_no_symbols, +. bfd_error_no_armap, +. bfd_error_no_more_archived_files, +. bfd_error_malformed_archive, +. bfd_error_file_not_recognized, +. bfd_error_file_ambiguously_recognized, +. bfd_error_no_contents, +. bfd_error_nonrepresentable_section, +. bfd_error_no_debug_section, +. bfd_error_bad_value, +. bfd_error_file_truncated, +. bfd_error_file_too_big, +. bfd_error_invalid_error_code +.} bfd_error_type; +. +*/ + +#undef strerror +extern char *strerror(); + +static bfd_error_type bfd_error = bfd_error_no_error; + +CONST char *CONST bfd_errmsgs[] = { + "No error", + "System call error", + "Invalid bfd target", + "File in wrong format", + "Invalid operation", + "Memory exhausted", + "No symbols", + "Archive has no index; run ranlib to add one", + "No more archived files", + "Malformed archive", + "File format not recognized", + "File format is ambiguous", + "Section has no contents", + "Nonrepresentable section on output", + "Symbol needs debug section which does not exist", + "Bad value", + "File truncated", + "File too big", + "#" + }; + +/* +FUNCTION + bfd_get_error + +SYNOPSIS + bfd_error_type bfd_get_error (void); + +DESCRIPTION + Return the current BFD error condition. */ -bfd_ec bfd_error = no_error; - -char *bfd_errmsgs[] = { "No error", - "System call error", - "Invalid target", - "File in wrong format", - "Invalid operation", - "Memory exhausted", - "No symbols", - "No relocation info", - "No more archived files", - "Malformed archive", - "Symbol not found", - "File format not recognized", - "File format is ambiguous", - "Section has no contents", - "Nonrepresentable section on output", - "#" - }; - -static -void -DEFUN(bfd_nonrepresentable_section,(abfd, name), - CONST bfd * CONST abfd AND - CONST char * CONST name) +bfd_error_type +bfd_get_error () { - printf("bfd error writing file %s, format %s can't represent section %s\n", - abfd->filename, - abfd->xvec->name, - name); - exit(1); + return bfd_error; } -bfd_error_vector_type bfd_error_vector = - { - bfd_nonrepresentable_section - }; +/* +FUNCTION + bfd_set_error + +SYNOPSIS + void bfd_set_error (bfd_error_type error_tag); -#if !defined(ANSI_LIBRARIES) -char * -strerror (code) - int code; -{ - extern int sys_nerr; - extern char *sys_errlist[]; +DESCRIPTION + Set the BFD error condition to be @var{error_tag}. +*/ - return (((code < 0) || (code >= sys_nerr)) ? "(unknown error)" : - sys_errlist [code]); +void +bfd_set_error (error_tag) + bfd_error_type error_tag; +{ + bfd_error = error_tag; } -#endif /* not ANSI_LIBRARIES */ +/* +FUNCTION + bfd_errmsg -char * +SYNOPSIS + CONST char *bfd_errmsg (bfd_error_type error_tag); + +DESCRIPTION + Return a string describing the error @var{error_tag}, or + the system error if @var{error_tag} is <>. +*/ + +CONST char * bfd_errmsg (error_tag) - bfd_ec error_tag; + bfd_error_type error_tag; { - - if (error_tag == system_call_error) +#ifndef errno + extern int errno; +#endif + if (error_tag == bfd_error_system_call) return strerror (errno); - if ((((int)error_tag <(int) no_error) || - ((int)error_tag > (int)invalid_error_code))) - error_tag = invalid_error_code;/* sanity check */ + if ((((int)error_tag <(int) bfd_error_no_error) || + ((int)error_tag > (int)bfd_error_invalid_error_code))) + error_tag = bfd_error_invalid_error_code;/* sanity check */ return bfd_errmsgs [(int)error_tag]; } - -void bfd_default_error_trap(error_tag) -bfd_ec error_tag; -{ - printf("bfd assert fail (%s)\n", bfd_errmsg(error_tag)); -} - -void (*bfd_error_trap)() = bfd_default_error_trap; -void (*bfd_error_nonrepresentabltrap)() = bfd_default_error_trap; +/* +FUNCTION + bfd_perror + +SYNOPSIS + void bfd_perror (CONST char *message); + +DESCRIPTION + Print to the standard error stream a string describing the + last BFD error that occurred, or the last system error if + the last BFD error was a system call failure. If @var{message} + is non-NULL and non-empty, the error string printed is preceded + by @var{message}, a colon, and a space. It is followed by a newline. +*/ void -DEFUN(bfd_perror,(message), - CONST char *message) +bfd_perror (message) + CONST char *message; { - if (bfd_error == system_call_error) - perror((char *)message); /* must be system error then... */ + if (bfd_get_error () == bfd_error_system_call) + perror((char *)message); /* must be system error then... */ else { if (message == NULL || *message == '\0') - fprintf (stderr, "%s\n", bfd_errmsg (bfd_error)); + fprintf (stderr, "%s\n", bfd_errmsg (bfd_get_error ())); else - fprintf (stderr, "%s: %s\n", message, bfd_errmsg (bfd_error)); + fprintf (stderr, "%s: %s\n", message, bfd_errmsg (bfd_get_error ())); } } -/* for error messages */ -char * -bfd_format_string (format) - bfd_format format; -{ - if (((int)format <(int) bfd_unknown) || ((int)format >=(int) bfd_type_end)) return "invalid"; - - switch (format) { - case bfd_object: return "object"; /* linker/assember/compiler output */ - case bfd_archive: return "archive"; /* object archive file */ - case bfd_core: return "core"; /* core dump */ - default: return "unknown"; - } -} - -/** Target configurations */ +/* +SUBSECTION + BFD error handler -extern bfd_target *target_vector[]; + Some BFD functions want to print messages describing the + problem. They call a BFD error handler function. This + function may be overriden by the program. -/* Returns a pointer to the transfer vector for the object target - named target_name. If target_name is NULL, chooses the one in the - environment variable GNUTARGET; if that is null or not defined then - the first entry in the target list is chosen. Passing in the - string "default" or setting the environment variable to "default" - will cause the first entry in the target list to be returned. */ + The BFD error handler acts like printf. -bfd_target * -DEFUN(bfd_find_target,(target_name), - CONST char *target_name) -{ - bfd_target **target; - extern char *getenv (); - CONST char *targname = (target_name ? target_name : getenv ("GNUTARGET")); +CODE_FRAGMENT +. +.typedef void (*bfd_error_handler_type) PARAMS ((const char *, ...)); +. +*/ - /* This is safe; the vector cannot be null */ - if (targname == NULL || !strcmp (targname, "default")) - return target_vector[0]; +/* The program name used when printing BFD error messages. */ - for (target = &target_vector[0]; *target != NULL; target++) { - if (!strcmp (targname, (*target)->name)) - return *target; - } +static const char *_bfd_error_program_name; - bfd_error = invalid_target; - return NULL; -} +/* This is the default routine to handle BFD error messages. */ + +#ifdef ANSI_PROTOTYPES -/* Returns a freshly-consed, NULL-terminated vector of the names of all the - valid bfd targets. Do not modify the names */ +static void _bfd_default_error_handler PARAMS ((const char *s, ...)); -char ** -bfd_target_list () +static void +_bfd_default_error_handler (const char *s, ...) { - int vec_length= 0; - bfd_target **target; - char **name_list, **name_ptr; + va_list p; - for (target = &target_vector[0]; *target != NULL; target++) - vec_length++; + if (_bfd_error_program_name != NULL) + fprintf (stderr, "%s: ", _bfd_error_program_name); - name_ptr = name_list = (char **) zalloc ((vec_length + 1) * sizeof (char **)); + va_start (p, s); - if (name_list == NULL) { - bfd_error = no_memory; - return NULL; - } + vfprintf (stderr, s, p); - for (target = &target_vector[0]; *target != NULL; target++) - *(name_ptr++) = (*target)->name; + va_end (p); - return name_list; + fprintf (stderr, "\n"); } - -/** Init a bfd for read of the proper format. - */ -/* We should be able to find out if the target was defaulted or user-specified. - If the user specified the target explicitly then we should do no search. - I guess the best way to do this is to pass an extra argument which specifies - the DWIM. */ +#else /* ! defined (ANSI_PROTOTYPES) */ -/* I have chanegd this always to set the filepos to the origin before - guessing. -- Gumby, 14 Februar 1991*/ +static void _bfd_default_error_handler (); -boolean -bfd_check_format (abfd, format) - bfd *abfd; - bfd_format format; +static void +_bfd_default_error_handler (va_alist) + va_dcl { - bfd_target **target, *save_targ, *right_targ; - int match_count; + va_list p; + const char *s; - if (!bfd_read_p (abfd) || - ((int)(abfd->format) < (int)bfd_unknown) || - ((int)(abfd->format) >= (int)bfd_type_end)) { - bfd_error = invalid_operation; - return false; - } - - if (abfd->format != bfd_unknown) return (abfd->format == format) ? true:false; - - /* presume the answer is yes */ - abfd->format = format; + if (_bfd_error_program_name != NULL) + fprintf (stderr, "%s: ", _bfd_error_program_name); - bfd_seek (abfd, (file_ptr)0, SEEK_SET); /* rewind! */ - - right_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); - if (right_targ) { - abfd->xvec = right_targ; /* Set the target as returned */ - return true; /* File position has moved, BTW */ - } + va_start (p); - /* This isn't a file in the specified or defaulted target type. - See if we recognize it for any other target type. (We check them - all to make sure it's uniquely recognized.) */ - - save_targ = abfd->xvec; - match_count = 0; - right_targ = 0; - - for (target = target_vector; *target != NULL; target++) { - bfd_target *temp; - - abfd->xvec = *target; /* Change BFD's target temporarily */ - bfd_seek (abfd, (file_ptr)0, SEEK_SET); - temp = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); - if (temp) { /* This format checks out as ok! */ - right_targ = temp; - match_count++; -#ifdef GNU960 - /* Big- and little-endian b.out archives look the same, but it doesn't - * matter: there is no difference in their headers, and member file byte - * orders will (I hope) be handled appropriately by bfd. Ditto for big - * and little coff archives. And the 4 coff/b.out object formats are - * unambiguous. So accept the first match we find. - */ - break; -#endif - } - } + s = va_arg (p, const char *); + vfprintf (stderr, s, p); - if (match_count == 1) { - abfd->xvec = right_targ; /* Change BFD's target permanently */ - return true; /* File position has moved, BTW */ - } + va_end (p); - abfd->xvec = save_targ; /* Restore original target type */ - abfd->format = bfd_unknown; /* Restore original format */ - bfd_error = ((match_count == 0) ? file_not_recognized : - file_ambiguously_recognized); - return false; + fprintf (stderr, "\n"); } -boolean -bfd_set_format (abfd, format) - bfd *abfd; - bfd_format format; -{ +#endif /* ! defined (ANSI_PROTOTYPES) */ - if (bfd_read_p (abfd) || - ((int)abfd->format < (int)bfd_unknown) || - ((int)abfd->format >= (int)bfd_type_end)) { - bfd_error = invalid_operation; - return false; - } +/* This is a function pointer to the routine which should handle BFD + error messages. It is called when a BFD routine encounters an + error for which it wants to print a message. Going through a + function pointer permits a program linked against BFD to intercept + the messages and deal with them itself. */ - if (abfd->format != bfd_unknown) return (abfd->format == format) ? true:false; +bfd_error_handler_type _bfd_error_handler = _bfd_default_error_handler; - /* presume the answer is yes */ - abfd->format = format; +/* +FUNCTION + bfd_set_error_handler - if (!BFD_SEND_FMT (abfd, _bfd_set_format, (abfd))) { - abfd->format = bfd_unknown; - return false; - } +SYNOPSIS + bfd_error_handler_type bfd_set_error_handler (bfd_error_handler_type); - return true; -} - -/* Hack object and core file sections */ +DESCRIPTION + Set the BFD error handler function. Returns the previous + function. +*/ -sec_ptr -DEFUN(bfd_get_section_by_name,(abfd, name), - bfd *abfd AND - CONST char *name) +bfd_error_handler_type +bfd_set_error_handler (pnew) + bfd_error_handler_type pnew; { - asection *sect; - - for (sect = abfd->sections; sect != NULL; sect = sect->next) - if (!strcmp (sect->name, name)) return sect; - return NULL; + bfd_error_handler_type pold; + + pold = _bfd_error_handler; + _bfd_error_handler = pnew; + return pold; } -/* If you try to create a section with a name which is already in use, - returns the old section by that name instead. */ -sec_ptr -DEFUN(bfd_make_section,(abfd, name), - bfd *abfd AND - CONST char *name) -{ - asection *newsect; - asection ** prev = &abfd->sections; - asection * sect = abfd->sections; - - if (abfd->output_has_begun) { - bfd_error = invalid_operation; - return NULL; - } +/* +FUNCTION + bfd_set_error_program_name - while (sect) { - if (!strcmp(sect->name, name)) return sect; - prev = §->next; - sect = sect->next; - } +SYNOPSIS + void bfd_set_error_program_name (const char *); - newsect = (asection *) bfd_zalloc(abfd, sizeof (asection)); - if (newsect == NULL) { - bfd_error = no_memory; - return NULL; - } +DESCRIPTION + Set the program name to use when printing a BFD error. This + is printed before the error message followed by a colon and + space. The string must not be changed after it is passed to + this function. +*/ - newsect->name = name; - newsect->index = abfd->section_count++; - newsect->flags = SEC_NO_FLAGS; +void +bfd_set_error_program_name (name) + const char *name; +{ + _bfd_error_program_name = name; +} + +/* +SECTION + Symbols +*/ - newsect->userdata = 0; - newsect->next = (asection *)NULL; - newsect->relocation = (arelent *)NULL; - newsect->reloc_count = 0; - newsect->line_filepos =0; +/* +FUNCTION + bfd_get_reloc_upper_bound - if (BFD_SEND (abfd, _new_section_hook, (abfd, newsect)) != true) { - free (newsect); - return NULL; - } +SYNOPSIS + long bfd_get_reloc_upper_bound(bfd *abfd, asection *sect); - *prev = newsect; - return newsect; -} +DESCRIPTION + Return the number of bytes required to store the + relocation information associated with section @var{sect} + attached to bfd @var{abfd}. If an error occurs, return -1. -/* Call operation on each section. Operation gets three args: the bfd, - the section, and a void * pointer (whatever the user supplied). */ +*/ -/* This is attractive except that without lexical closures its use is hard - to make reentrant. */ -/*VARARGS2*/ -void -bfd_map_over_sections (abfd, operation, user_storage) - bfd *abfd; - void (*operation)(); - PTR user_storage; -{ - asection *sect; - int i = 0; - - for (sect = abfd->sections; sect != NULL; i++, sect = sect->next) - (*operation) (abfd, sect, user_storage); - - if (i != abfd->section_count) /* Debugging */ - abort(); -} -boolean -bfd_set_section_flags (abfd, section, flags) +long +bfd_get_reloc_upper_bound (abfd, asect) bfd *abfd; - sec_ptr section; - flagword flags; + sec_ptr asect; { - if ((flags & bfd_applicable_section_flags (abfd)) != flags) { - bfd_error = invalid_operation; - return false; + if (abfd->format != bfd_object) { + bfd_set_error (bfd_error_invalid_operation); + return -1; } - section->flags = flags; -return true; + return BFD_SEND (abfd, _get_reloc_upper_bound, (abfd, asect)); } +/* +FUNCTION + bfd_canonicalize_reloc -boolean -bfd_set_section_size (abfd, ptr, val) - bfd *abfd; - sec_ptr ptr; - unsigned long val; -{ - /* Once you've started writing to any section you cannot create or change - the size of any others. */ +SYNOPSIS + long bfd_canonicalize_reloc + (bfd *abfd, + asection *sec, + arelent **loc, + asymbol **syms); - if (abfd->output_has_begun) { - bfd_error = invalid_operation; - return false; - } +DESCRIPTION + Call the back end associated with the open BFD + @var{abfd} and translate the external form of the relocation + information attached to @var{sec} into the internal canonical + form. Place the table into memory at @var{loc}, which has + been preallocated, usually by a call to + <>. Returns the number of relocs, or + -1 on error. - ptr->size = val; - - return true; -} + The @var{syms} table is also needed for horrible internal magic + reasons. -boolean -bfd_set_section_contents (abfd, section, location, offset, count) + +*/ +long +bfd_canonicalize_reloc (abfd, asect, location, symbols) bfd *abfd; - sec_ptr section; - PTR location; - file_ptr offset; - int count; + sec_ptr asect; + arelent **location; + asymbol **symbols; { - if (!(bfd_get_section_flags(abfd, section) & - SEC_HAS_CONTENTS)) { - bfd_error = no_contents; - return(false); - } /* if section has no contents */ - - if (BFD_SEND (abfd, _bfd_set_section_contents, - (abfd, section, location, offset, count))) { - abfd->output_has_begun = true; - return true; + if (abfd->format != bfd_object) { + bfd_set_error (bfd_error_invalid_operation); + return -1; } - - return false; + return BFD_SEND (abfd, _bfd_canonicalize_reloc, + (abfd, asect, location, symbols)); } -boolean -bfd_get_section_contents (abfd, section, location, offset, count) - bfd *abfd; - sec_ptr section; - PTR location; - file_ptr offset; - int count; +/* +FUNCTION + bfd_set_reloc + +SYNOPSIS + void bfd_set_reloc + (bfd *abfd, asection *sec, arelent **rel, unsigned int count) + +DESCRIPTION + Set the relocation pointer and count within + section @var{sec} to the values @var{rel} and @var{count}. + The argument @var{abfd} is ignored. + +*/ +/*ARGSUSED*/ +void +bfd_set_reloc (ignore_abfd, asect, location, count) + bfd *ignore_abfd; + sec_ptr asect; + arelent **location; + unsigned int count; { - if (section->flags & SEC_CONSTRUCTOR) { - memset(location, 0, count); - return true; - } - else { - return (BFD_SEND (abfd, _bfd_get_section_contents, - (abfd, section, location, offset, count))); - } + asect->orelocation = location; + asect->reloc_count = count; } - -/** Some core file info commands */ +/* +FUNCTION + bfd_set_file_flags + +SYNOPSIS + boolean bfd_set_file_flags(bfd *abfd, flagword flags); + +DESCRIPTION + Set the flag word in the BFD @var{abfd} to the value @var{flags}. -/* Returns a read-only string explaining what program was running when - it failed. */ + Possible errors are: + o <> - The target bfd was not of object format. + o <> - The target bfd was open for reading. + o <> - + The flag word contained a bit which was not applicable to the + type of file. E.g., an attempt was made to set the <> bit + on a BFD format which does not support demand paging. + +*/ -char * -bfd_core_file_failing_command (abfd) +boolean +bfd_set_file_flags (abfd, flags) bfd *abfd; + flagword flags; { - if (abfd->format != bfd_core) { - bfd_error = invalid_operation; - return NULL; + if (abfd->format != bfd_object) { + bfd_set_error (bfd_error_wrong_format); + return false; } - return BFD_SEND (abfd, _core_file_failing_command, (abfd)); -} -int -bfd_core_file_failing_signal (abfd) - bfd *abfd; -{ - if (abfd->format != bfd_core) { - bfd_error = invalid_operation; - return NULL; + if (bfd_read_p (abfd)) { + bfd_set_error (bfd_error_invalid_operation); + return false; } - return BFD_SEND (abfd, _core_file_failing_signal, (abfd)); -} -boolean -core_file_matches_executable_p (core_bfd, exec_bfd) - bfd *core_bfd, *exec_bfd; -{ - if ((core_bfd->format != bfd_core) || (exec_bfd->format != bfd_object)) { - bfd_error = wrong_format; + bfd_get_file_flags (abfd) = flags; + if ((flags & bfd_applicable_file_flags (abfd)) != flags) { + bfd_set_error (bfd_error_invalid_operation); return false; } - return BFD_SEND (core_bfd, _core_file_matches_executable_p, (core_bfd, exec_bfd)); +return true; } - -/** Symbols */ -boolean -bfd_set_symtab (abfd, location, symcount) - bfd *abfd; - asymbol **location; - unsigned int symcount; +void +bfd_assert (file, line) + const char *file; + int line; { - if ((abfd->format != bfd_object) || (bfd_read_p (abfd))) { - bfd_error = invalid_operation; - return false; - } + (*_bfd_error_handler) ("bfd assertion fail %s:%d", file, line); +} + + +/* +FUNCTION + bfd_set_start_address - bfd_get_outsymbols (abfd) = location; - bfd_get_symcount (abfd) = symcount; +SYNOPSIS + boolean bfd_set_start_address(bfd *abfd, bfd_vma vma); + +DESCRIPTION + Make @var{vma} the entry point of output BFD @var{abfd}. + +RETURNS + Returns <> on success, <> otherwise. +*/ + +boolean +bfd_set_start_address(abfd, vma) +bfd *abfd; +bfd_vma vma; +{ + abfd->start_address = vma; return true; } -/* returns the number of octets of storage required */ -unsigned int -get_reloc_upper_bound (abfd, asect) + +/* +FUNCTION + bfd_get_mtime + +SYNOPSIS + long bfd_get_mtime(bfd *abfd); + +DESCRIPTION + Return the file modification time (as read from the file system, or + from the archive header for archive members). + +*/ + +long +bfd_get_mtime (abfd) bfd *abfd; - sec_ptr asect; { - if (abfd->format != bfd_object) { - bfd_error = invalid_operation; + FILE *fp; + struct stat buf; + + if (abfd->mtime_set) + return abfd->mtime; + + fp = bfd_cache_lookup (abfd); + if (0 != fstat (fileno (fp), &buf)) return 0; - } - return BFD_SEND (abfd, _get_reloc_upper_bound, (abfd, asect)); + abfd->mtime = buf.st_mtime; /* Save value in case anyone wants it */ + return buf.st_mtime; } -unsigned int -bfd_canonicalize_reloc (abfd, asect, location, symbols) +/* +FUNCTION + bfd_get_size + +SYNOPSIS + long bfd_get_size(bfd *abfd); + +DESCRIPTION + Return the file size (as read from file system) for the file + associated with BFD @var{abfd}. + + The initial motivation for, and use of, this routine is not + so we can get the exact size of the object the BFD applies to, since + that might not be generally possible (archive members for example). + It would be ideal if someone could eventually modify + it so that such results were guaranteed. + + Instead, we want to ask questions like "is this NNN byte sized + object I'm about to try read from file offset YYY reasonable?" + As as example of where we might do this, some object formats + use string tables for which the first <> bytes of the + table contain the size of the table itself, including the size bytes. + If an application tries to read what it thinks is one of these + string tables, without some way to validate the size, and for + some reason the size is wrong (byte swapping error, wrong location + for the string table, etc.), the only clue is likely to be a read + error when it tries to read the table, or a "virtual memory + exhausted" error when it tries to allocate 15 bazillon bytes + of space for the 15 bazillon byte table it is about to read. + This function at least allows us to answer the quesion, "is the + size reasonable?". +*/ + +long +bfd_get_size (abfd) bfd *abfd; - sec_ptr asect; - arelent **location; - asymbol **symbols; { - if (abfd->format != bfd_object) { - bfd_error = invalid_operation; + FILE *fp; + struct stat buf; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + return ((struct bfd_in_memory *) abfd->iostream)->size; + + fp = bfd_cache_lookup (abfd); + if (0 != fstat (fileno (fp), &buf)) return 0; - } - return BFD_SEND (abfd, _bfd_canonicalize_reloc, (abfd, asect, location, symbols)); + return buf.st_size; } -void -bfd_print_symbol_vandf(file, symbol) -PTR file; -asymbol *symbol; +/* +FUNCTION + bfd_get_gp_size + +SYNOPSIS + int bfd_get_gp_size(bfd *abfd); + +DESCRIPTION + Return the maximum size of objects to be optimized using the GP + register under MIPS ECOFF. This is typically set by the <<-G>> + argument to the compiler, assembler or linker. +*/ + +int +bfd_get_gp_size (abfd) + bfd *abfd; { - flagword type = symbol->flags; - if (symbol->section != (asection *)NULL) - { - fprintf(file,"%08lx ", symbol->value+symbol->section->vma); - } - else + if (abfd->format == bfd_object) { - fprintf(file,"%08lx ", symbol->value); + if (abfd->xvec->flavour == bfd_target_ecoff_flavour) + return ecoff_data (abfd)->gp_size; + else if (abfd->xvec->flavour == bfd_target_elf_flavour) + return elf_gp_size (abfd); } - fprintf(file,"%c%c%c%c%c%c%c", - (type & BSF_LOCAL) ? 'l':' ', - (type & BSF_GLOBAL) ? 'g' : ' ', - (type & BSF_IMPORT) ? 'i' : ' ', - (type & BSF_EXPORT) ? 'e' : ' ', - (type & BSF_UNDEFINED) ? 'u' : ' ', - (type & BSF_FORT_COMM) ? 'c' : ' ', - (type & BSF_DEBUGGING) ? 'd' :' '); - + return 0; } +/* +FUNCTION + bfd_set_gp_size -boolean -bfd_set_file_flags (abfd, flags) +SYNOPSIS + void bfd_set_gp_size(bfd *abfd, int i); + +DESCRIPTION + Set the maximum size of objects to be optimized using the GP + register under ECOFF or MIPS ELF. This is typically set by + the <<-G>> argument to the compiler, assembler or linker. +*/ + +void +bfd_set_gp_size (abfd, i) bfd *abfd; - flagword flags; + int i; { - if (abfd->format != bfd_object) { - bfd_error = wrong_format; - return false; - } - - if (bfd_read_p (abfd)) { - bfd_error = invalid_operation; - return false; - } + /* Don't try to set GP size on an archive or core file! */ + if (abfd->format != bfd_object) + return; + if (abfd->xvec->flavour == bfd_target_ecoff_flavour) + ecoff_data (abfd)->gp_size = i; + else if (abfd->xvec->flavour == bfd_target_elf_flavour) + elf_gp_size (abfd) = i; +} - if ((flags & bfd_applicable_file_flags (abfd)) != flags) { - bfd_error = invalid_operation; - return false; - } +/* Get the GP value. This is an internal function used by some of the + relocation special_function routines on targets which support a GP + register. */ - bfd_get_file_flags (abfd) = flags; -return true; +bfd_vma +_bfd_get_gp_value (abfd) + bfd *abfd; +{ + if (abfd->format == bfd_object) + { + if (abfd->xvec->flavour == bfd_target_ecoff_flavour) + return ecoff_data (abfd)->gp; + else if (abfd->xvec->flavour == bfd_target_elf_flavour) + return elf_gp (abfd); + } + return 0; } +/* Set the GP value. */ void -bfd_set_reloc (ignore_abfd, asect, location, count) - bfd *ignore_abfd; - sec_ptr asect; - arelent **location; - unsigned int count; +_bfd_set_gp_value (abfd, v) + bfd *abfd; + bfd_vma v; { - asect->orelocation = location; - asect->reloc_count = count; + if (abfd->format != bfd_object) + return; + if (abfd->xvec->flavour == bfd_target_ecoff_flavour) + ecoff_data (abfd)->gp = v; + else if (abfd->xvec->flavour == bfd_target_elf_flavour) + elf_gp (abfd) = v; } + /* -If an output_bfd is supplied to this function the generated image -will be relocatable, the relocations are copied to the output file -after they have been changed to reflect the new state of the world. -There are two ways of reflecting the results of partial linkage in an -output file; by modifying the output data in place, and by modifying -the relocation record. Some native formats (eg basic a.out and basic -coff) have no way of specifying an addend in the relocation type, so -the addend has to go in the output data. This is no big deal since in -these formats the output data slot will always be big enough for the -addend. Complex reloc types with addends were invented to solve just -this problem. +FUNCTION + bfd_scan_vma + +SYNOPSIS + bfd_vma bfd_scan_vma(CONST char *string, CONST char **end, int base); + +DESCRIPTION + Convert, like <>, a numerical expression + @var{string} into a <> integer, and return that integer. + (Though without as many bells and whistles as <>.) + The expression is assumed to be unsigned (i.e., positive). + If given a @var{base}, it is used as the base for conversion. + A base of 0 causes the function to interpret the string + in hex if a leading "0x" or "0X" is found, otherwise + in octal if a leading zero is found, otherwise in decimal. + + Overflow is not detected. */ -bfd_reloc_status_enum_type -bfd_perform_relocation(abfd, - reloc_entry, - data, - input_section, - output_bfd) -bfd *abfd; -arelent *reloc_entry; -PTR data; -asection *input_section; -bfd *output_bfd; +bfd_vma +bfd_scan_vma (string, end, base) + CONST char *string; + CONST char **end; + int base; { - bfd_vma relocation; - bfd_reloc_status_enum_type flag = bfd_reloc_ok; - bfd_vma relocation_before; - bfd_vma addr = reloc_entry->address ; - bfd_vma output_base = 0; - reloc_howto_type *howto = reloc_entry->howto; - asection *reloc_target_output_section; - asection *reloc_target_input_section; - asymbol *symbol; - - if (reloc_entry->sym_ptr_ptr) { - symbol = *( reloc_entry->sym_ptr_ptr); - if ((symbol->flags & BSF_UNDEFINED) && output_bfd == (bfd *)NULL) { - flag = bfd_reloc_undefined; - } - } - else { - symbol = (asymbol*)NULL; - } - - if (howto->special_function){ - bfd_reloc_status_enum_type cont; - cont = howto->special_function(abfd, - reloc_entry, - symbol, - data, - input_section); - if (cont != bfd_reloc_continue) return cont; - } + bfd_vma value; + int digit; - /* - Work out which section the relocation is targetted at and the - initial relocation command value. - */ + /* Let the host do it if possible. */ + if (sizeof(bfd_vma) <= sizeof(unsigned long)) + return (bfd_vma) strtoul (string, (char **) end, base); + /* A negative base makes no sense, and we only need to go as high as hex. */ + if ((base < 0) || (base > 16)) + return (bfd_vma) 0; - if (symbol != (asymbol *)NULL){ - if (symbol->flags & BSF_FORT_COMM) { - relocation = 0; - } - else { - relocation = symbol->value; - } - if (symbol->section != (asection *)NULL) + if (base == 0) + { + if (string[0] == '0') { - reloc_target_input_section = symbol->section; + if ((string[1] == 'x') || (string[1] == 'X')) + base = 16; + /* XXX should we also allow "0b" or "0B" to set base to 2? */ + else + base = 8; } - else { - reloc_target_input_section = (asection *)NULL; + else + base = 10; + } + if ((base == 16) && + (string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) + string += 2; + /* XXX should we also skip over "0b" or "0B" if base is 2? */ + +/* Speed could be improved with a table like hex_value[] in gas. */ +#define HEX_VALUE(c) \ + (isxdigit(c) ? \ + (isdigit(c) ? \ + (c - '0') : \ + (10 + c - (islower(c) ? 'a' : 'A'))) : \ + 42) + + for (value = 0; (digit = HEX_VALUE(*string)) < base; string++) + { + value = value * base + digit; } - } - else if (reloc_entry->section != (asection *)NULL) - { - relocation = 0; - reloc_target_input_section = reloc_entry->section; - } - else { - relocation = 0; - reloc_target_input_section = (asection *)NULL; - } + if (end) + *end = string; - if (reloc_target_input_section != (asection *)NULL) { + return value; +} - reloc_target_output_section = - reloc_target_input_section->output_section; +/* +FUNCTION + bfd_copy_private_bfd_data - if (output_bfd && howto->partial_inplace==false) { - output_base = 0; - } - else { - output_base = reloc_target_output_section->vma; +SYNOPSIS + boolean bfd_copy_private_bfd_data(bfd *ibfd, bfd *obfd); - } +DESCRIPTION + Copy private BFD information from the BFD @var{ibfd} to the + the BFD @var{obfd}. Return <> on success, <> on error. + Possible error returns are: - relocation += output_base + reloc_target_input_section->output_offset; - } + o <> - + Not enough memory exists to create private data for @var{obfd}. - relocation += reloc_entry->addend ; +.#define bfd_copy_private_bfd_data(ibfd, obfd) \ +. BFD_SEND (ibfd, _bfd_copy_private_bfd_data, \ +. (ibfd, obfd)) +*/ - if(reloc_entry->address > (bfd_vma)(input_section->size)) - { - return bfd_reloc_outofrange; - } - +/* +FUNCTION + bfd_merge_private_bfd_data - if (howto->pc_relative == true) - { - /* - Anything which started out as pc relative should end up that - way too. +SYNOPSIS + boolean bfd_merge_private_bfd_data(bfd *ibfd, bfd *obfd); - There are two ways we can see a pcrel instruction. Sometimes - the pcrel displacement has been partially calculated, it - includes the distance from the start of the section to the - instruction in it (eg sun3), and sometimes the field is - totally blank - eg m88kbcs. - */ +DESCRIPTION + Merge private BFD information from the BFD @var{ibfd} to the + the output file BFD @var{obfd} when linking. Return <> + on success, <> on error. Possible error returns are: - - relocation -= - output_base + input_section->output_offset; + o <> - + Not enough memory exists to create private data for @var{obfd}. - if (howto->pcrel_offset == true) { - relocation -= reloc_entry->address; - } +.#define bfd_merge_private_bfd_data(ibfd, obfd) \ +. BFD_SEND (ibfd, _bfd_merge_private_bfd_data, \ +. (ibfd, obfd)) - } - - if (output_bfd!= (bfd *)NULL) { - if ( howto->partial_inplace == false) { - /* - This is a partial relocation, and we want to apply the relocation - to the reloc entry rather than the raw data. Modify the reloc - inplace to reflect what we now know. - */ - reloc_entry->addend = relocation ; - reloc_entry->section = reloc_target_input_section; - if (reloc_target_input_section != (asection *)NULL) { - /* If we know the output section we can forget the symbol */ - reloc_entry->sym_ptr_ptr = (asymbol**)NULL; - } - reloc_entry->address += - input_section->output_offset; - return flag; - } - else - { - /* This is a partial relocation, but inplace, so modify the - reloc record a bit - */ +*/ - } - } +/* +FUNCTION + bfd_set_private_flags - reloc_entry->addend = 0; - - - /* - Either we are relocating all the way, or we don't want to apply - the relocation to the reloc entry (probably because there isn't - any room in the output format to describe addends to relocs) - */ - relocation >>= howto->rightshift; - - /* Shift everything up to where it's going to be used */ - - relocation <<= howto->bitpos; - - - /* Wait for the day when all have the mask in them */ - - - - relocation_before = relocation; - - - /* What we do: - i instruction to be left alone - o offset within instruction - r relocation offset to apply - S src mask - D dst mask - N ~dst mask - A part 1 - B part 2 - R result - - Do this: - i i i i i o o o o o from bfd_get - and S S S S S to get the size offset we want - + r r r r r r r r r r to get the final value to place - and D D D D D to chop to right size - ----------------------- - A A A A A - And this: - ... i i i i i o o o o o from bfd_get - and N N N N N get instruction - ----------------------- - ... B B B B B - - And then: - B B B B B - or A A A A A - ----------------------- - R R R R R R R R R R put into bfd_put - */ - -#define DOIT(x) \ - x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask)) - - switch (howto->size) - { - case 0: - { - char x = bfd_getchar(abfd, (char *)data + addr); - DOIT(x); - bfd_putchar(abfd,x, (unsigned char *) data + addr); - } - break; - - case 1: - { - short x = bfd_getshort(abfd, (bfd_byte *)data + addr); - DOIT(x); - bfd_putshort(abfd, x, (unsigned char *)data + addr); - } - break; - case 2: - { - long x = bfd_getlong(abfd, (bfd_byte *) data + addr); - DOIT(x); - bfd_putlong(abfd,x, (bfd_byte *)data + addr); - } - break; - case 3: - /* Do nothing */ - break; - default: - return bfd_reloc_other; - } +SYNOPSIS + boolean bfd_set_private_flags(bfd *abfd, flagword flags); - return flag; -} +DESCRIPTION + Set private BFD flag information in the BFD @var{abfd}. + Return <> on success, <> on error. Possible error + returns are: -void -bfd_assert(file, line) -char *file; -int line; -{ - printf("bfd assertion fail %s:%d\n",file,line); -} + o <> - + Not enough memory exists to create private data for @var{obfd}. +.#define bfd_set_private_flags(abfd, flags) \ +. BFD_SEND (abfd, _bfd_set_private_flags, \ +. (abfd, flags)) -boolean -bfd_set_start_address(abfd, vma) -bfd *abfd; -bfd_vma vma; -{ - abfd->start_address = vma; - return true; -} +*/ +/* +FUNCTION + stuff + +DESCRIPTION + Stuff which should be documented: + +.#define bfd_sizeof_headers(abfd, reloc) \ +. BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc)) +. +.#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ +. BFD_SEND (abfd, _bfd_find_nearest_line, (abfd, sec, syms, off, file, func, line)) +. +. {* Do these three do anything useful at all, for any back end? *} +.#define bfd_debug_info_start(abfd) \ +. BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) +. +.#define bfd_debug_info_end(abfd) \ +. BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) +. +.#define bfd_debug_info_accumulate(abfd, section) \ +. BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) +. +. +.#define bfd_stat_arch_elt(abfd, stat) \ +. BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) +. +.#define bfd_update_armap_timestamp(abfd) \ +. BFD_SEND (abfd, _bfd_update_armap_timestamp, (abfd)) +. +.#define bfd_set_arch_mach(abfd, arch, mach)\ +. BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) +. +.#define bfd_relax_section(abfd, section, link_info, again) \ +. BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again)) +. +.#define bfd_link_hash_table_create(abfd) \ +. BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd)) +. +.#define bfd_link_add_symbols(abfd, info) \ +. BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info)) +. +.#define bfd_final_link(abfd, info) \ +. BFD_SEND (abfd, _bfd_final_link, (abfd, info)) +. +.#define bfd_free_cached_info(abfd) \ +. BFD_SEND (abfd, _bfd_free_cached_info, (abfd)) +. +.#define bfd_get_dynamic_symtab_upper_bound(abfd) \ +. BFD_SEND (abfd, _bfd_get_dynamic_symtab_upper_bound, (abfd)) +. +.#define bfd_print_private_bfd_data(abfd, file)\ +. BFD_SEND (abfd, _bfd_print_private_bfd_data, (abfd, file)) +. +.#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \ +. BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols)) +. +.#define bfd_get_dynamic_reloc_upper_bound(abfd) \ +. BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd)) +. +.#define bfd_canonicalize_dynamic_reloc(abfd, arels, asyms) \ +. BFD_SEND (abfd, _bfd_canonicalize_dynamic_reloc, (abfd, arels, asyms)) +. +.extern bfd_byte *bfd_get_relocated_section_contents +. PARAMS ((bfd *, struct bfd_link_info *, +. struct bfd_link_order *, bfd_byte *, +. boolean, asymbol **)); +. + +*/ -bfd_vma bfd_log2(x) -bfd_vma x; +bfd_byte * +bfd_get_relocated_section_contents (abfd, link_info, link_order, data, + relocateable, symbols) + bfd *abfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + bfd_byte *data; + boolean relocateable; + asymbol **symbols; { - bfd_vma result = 0; - while ( (bfd_vma)(1<< result) < x) - result++; - return result; + bfd *abfd2; + bfd_byte *(*fn) PARAMS ((bfd *, struct bfd_link_info *, + struct bfd_link_order *, bfd_byte *, boolean, + asymbol **)); + + if (link_order->type == bfd_indirect_link_order) + { + abfd2 = link_order->u.indirect.section->owner; + if (abfd2 == 0) + abfd2 = abfd; + } + else + abfd2 = abfd; + fn = abfd2->xvec->_bfd_get_relocated_section_contents; + + return (*fn) (abfd, link_info, link_order, data, relocateable, symbols); } -/* bfd_get_mtime: Return cached file modification time (e.g. as read - from archive header for archive members, or from file system if we have - been called before); else determine modify time, cache it, and - return it. */ +/* Record information about an ELF program header. */ -long -bfd_get_mtime (abfd) +boolean +bfd_record_phdr (abfd, type, flags_valid, flags, at_valid, at, + includes_filehdr, includes_phdrs, count, secs) bfd *abfd; + unsigned long type; + boolean flags_valid; + flagword flags; + boolean at_valid; + bfd_vma at; + boolean includes_filehdr; + boolean includes_phdrs; + unsigned int count; + asection **secs; { - FILE *fp; - struct stat buf; + struct elf_segment_map *m, **pm; - if (abfd->mtime_set) - return abfd->mtime; + if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) + return true; - fp = bfd_cache_lookup (abfd); - if (0 != fstat (fileno (fp), &buf)) - return 0; + m = ((struct elf_segment_map *) + bfd_alloc (abfd, + (sizeof (struct elf_segment_map) + + (count - 1) * sizeof (asection *)))); + if (m == NULL) + return false; - abfd->mtime_set = true; - abfd->mtime = buf.st_mtime; - return abfd->mtime; + m->next = NULL; + m->p_type = type; + m->p_flags = flags; + m->p_paddr = at; + m->p_flags_valid = flags_valid; + m->p_paddr_valid = at_valid; + m->includes_filehdr = includes_filehdr; + m->includes_phdrs = includes_phdrs; + m->count = count; + if (count > 0) + memcpy (m->sections, secs, count * sizeof (asection *)); + + for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL; pm = &(*pm)->next) + ; + *pm = m; + + return true; }