+RETURNS
+ Returns <<TRUE>> on success, <<FALSE>> otherwise.
+*/
+
+bfd_boolean
+bfd_set_start_address (bfd *abfd, bfd_vma vma)
+{
+ abfd->start_address = vma;
+ return TRUE;
+}
+
+/*
+FUNCTION
+ bfd_get_gp_size
+
+SYNOPSIS
+ unsigned 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.
+*/
+
+unsigned int
+bfd_get_gp_size (bfd *abfd)
+{
+ if (abfd->format == bfd_object)
+ {
+ 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);
+ }
+ return 0;
+}
+
+/*
+FUNCTION
+ bfd_set_gp_size
+
+SYNOPSIS
+ void bfd_set_gp_size (bfd *abfd, unsigned 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 (bfd *abfd, unsigned int i)
+{
+ /* 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;
+}
+
+/* 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_vma
+_bfd_get_gp_value (bfd *abfd)
+{
+ if (! abfd)
+ return 0;
+ if (abfd->format != bfd_object)
+ return 0;
+
+ 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_gp_value (bfd *abfd, bfd_vma v)
+{
+ if (! abfd)
+ abort ();
+ 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;
+}
+
+/*
+FUNCTION
+ bfd_scan_vma
+
+SYNOPSIS
+ bfd_vma bfd_scan_vma (const char *string, const char **end, int base);
+
+DESCRIPTION
+ Convert, like <<strtoul>>, a numerical expression
+ @var{string} into a <<bfd_vma>> integer, and return that integer.
+ (Though without as many bells and whistles as <<strtoul>>.)
+ 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.
+
+ If the value would overflow, the maximum <<bfd_vma>> value is
+ returned.
+*/
+
+bfd_vma
+bfd_scan_vma (const char *string, const char **end, int base)
+{
+ bfd_vma value;
+ bfd_vma cutoff;
+ unsigned int cutlim;
+ int overflow;
+
+ /* Let the host do it if possible. */
+ if (sizeof (bfd_vma) <= sizeof (unsigned long))
+ return strtoul (string, (char **) end, base);
+
+#ifdef HAVE_STRTOULL
+ if (sizeof (bfd_vma) <= sizeof (unsigned long long))
+ return strtoull (string, (char **) end, base);
+#endif
+
+ if (base == 0)
+ {
+ if (string[0] == '0')
+ {
+ if ((string[1] == 'x') || (string[1] == 'X'))
+ base = 16;
+ else
+ base = 8;
+ }
+ }
+
+ if ((base < 2) || (base > 36))
+ base = 10;
+
+ if (base == 16
+ && string[0] == '0'
+ && (string[1] == 'x' || string[1] == 'X')
+ && ISXDIGIT (string[2]))
+ {
+ string += 2;
+ }
+
+ cutoff = (~ (bfd_vma) 0) / (bfd_vma) base;
+ cutlim = (~ (bfd_vma) 0) % (bfd_vma) base;
+ value = 0;
+ overflow = 0;
+ while (1)
+ {
+ unsigned int digit;
+
+ digit = *string;
+ if (ISDIGIT (digit))
+ digit = digit - '0';
+ else if (ISALPHA (digit))
+ digit = TOUPPER (digit) - 'A' + 10;
+ else
+ break;
+ if (digit >= (unsigned int) base)
+ break;
+ if (value > cutoff || (value == cutoff && digit > cutlim))
+ overflow = 1;
+ value = value * base + digit;
+ ++string;
+ }
+
+ if (overflow)
+ value = ~ (bfd_vma) 0;
+
+ if (end != NULL)
+ *end = string;
+
+ return value;
+}
+
+/*
+FUNCTION
+ bfd_copy_private_header_data
+
+SYNOPSIS
+ bfd_boolean bfd_copy_private_header_data (bfd *ibfd, bfd *obfd);
+
+DESCRIPTION
+ Copy private BFD header information from the BFD @var{ibfd} to the
+ the BFD @var{obfd}. This copies information that may require
+ sections to exist, but does not require symbol tables. Return
+ <<true>> on success, <<false>> on error.
+ Possible error returns are:
+
+ o <<bfd_error_no_memory>> -
+ Not enough memory exists to create private data for @var{obfd}.
+
+.#define bfd_copy_private_header_data(ibfd, obfd) \
+. BFD_SEND (obfd, _bfd_copy_private_header_data, \
+. (ibfd, obfd))
+
+*/
+
+/*
+FUNCTION
+ bfd_copy_private_bfd_data
+
+SYNOPSIS
+ bfd_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 <<TRUE>> on success, <<FALSE>> on error.
+ Possible error returns are:
+
+ o <<bfd_error_no_memory>> -
+ Not enough memory exists to create private data for @var{obfd}.
+
+.#define bfd_copy_private_bfd_data(ibfd, obfd) \
+. BFD_SEND (obfd, _bfd_copy_private_bfd_data, \
+. (ibfd, obfd))
+
+*/
+
+/*
+FUNCTION
+ bfd_merge_private_bfd_data
+
+SYNOPSIS
+ bfd_boolean bfd_merge_private_bfd_data (bfd *ibfd, bfd *obfd);
+
+DESCRIPTION
+ Merge private BFD information from the BFD @var{ibfd} to the
+ the output file BFD @var{obfd} when linking. Return <<TRUE>>
+ on success, <<FALSE>> on error. Possible error returns are:
+
+ o <<bfd_error_no_memory>> -
+ Not enough memory exists to create private data for @var{obfd}.
+
+.#define bfd_merge_private_bfd_data(ibfd, obfd) \
+. BFD_SEND (obfd, _bfd_merge_private_bfd_data, \
+. (ibfd, obfd))
+
+*/
+
+/*
+FUNCTION
+ bfd_set_private_flags
+
+SYNOPSIS
+ bfd_boolean bfd_set_private_flags (bfd *abfd, flagword flags);
+
+DESCRIPTION
+ Set private BFD flag information in the BFD @var{abfd}.
+ Return <<TRUE>> on success, <<FALSE>> on error. Possible error
+ returns are:
+
+ o <<bfd_error_no_memory>> -
+ 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))
+
+*/
+
+/*
+FUNCTION
+ Other functions
+
+DESCRIPTION
+ The following functions exist but have not yet been documented.
+
+.#define bfd_sizeof_headers(abfd, info) \
+. BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, info))
+.
+.#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \
+. BFD_SEND (abfd, _bfd_find_nearest_line, \
+. (abfd, syms, sec, off, file, func, line, NULL))
+.
+.#define bfd_find_nearest_line_discriminator(abfd, sec, syms, off, file, func, \
+. line, disc) \
+. BFD_SEND (abfd, _bfd_find_nearest_line, \
+. (abfd, syms, sec, off, file, func, line, disc))
+.
+.#define bfd_find_line(abfd, syms, sym, file, line) \
+. BFD_SEND (abfd, _bfd_find_line, \
+. (abfd, syms, sym, file, line))
+.
+.#define bfd_find_inliner_info(abfd, file, func, line) \
+. BFD_SEND (abfd, _bfd_find_inliner_info, \
+. (abfd, file, func, line))
+.
+.#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_gc_sections(abfd, link_info) \
+. BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info))
+.
+.#define bfd_lookup_section_flags(link_info, flag_info, section) \
+. BFD_SEND (abfd, _bfd_lookup_section_flags, (link_info, flag_info, section))
+.
+.#define bfd_merge_sections(abfd, link_info) \
+. BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info))
+.
+.#define bfd_is_group_section(abfd, sec) \
+. BFD_SEND (abfd, _bfd_is_group_section, (abfd, sec))
+.
+.#define bfd_discard_group(abfd, sec) \
+. BFD_SEND (abfd, _bfd_discard_group, (abfd, sec))
+.
+.#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_link_just_syms(abfd, sec, info) \
+. BFD_SEND (abfd, _bfd_link_just_syms, (sec, 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_synthetic_symtab(abfd, count, syms, dyncount, dynsyms, ret) \
+. BFD_SEND (abfd, _bfd_get_synthetic_symtab, (abfd, count, syms, \
+. dyncount, dynsyms, ret))
+.
+.#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
+. (bfd *, struct bfd_link_info *, struct bfd_link_order *, bfd_byte *,
+. bfd_boolean, asymbol **);
+.
+
+*/
+
+bfd_byte *
+bfd_get_relocated_section_contents (bfd *abfd,
+ struct bfd_link_info *link_info,
+ struct bfd_link_order *link_order,
+ bfd_byte *data,
+ bfd_boolean relocatable,
+ asymbol **symbols)
+{
+ bfd *abfd2;
+ bfd_byte *(*fn) (bfd *, struct bfd_link_info *, struct bfd_link_order *,
+ bfd_byte *, bfd_boolean, asymbol **);
+
+ if (link_order->type == bfd_indirect_link_order)
+ {
+ abfd2 = link_order->u.indirect.section->owner;
+ if (abfd2 == NULL)
+ abfd2 = abfd;
+ }
+ else
+ abfd2 = abfd;
+
+ fn = abfd2->xvec->_bfd_get_relocated_section_contents;
+
+ return (*fn) (abfd, link_info, link_order, data, relocatable, symbols);
+}
+
+/* Record information about an ELF program header. */
+
+bfd_boolean
+bfd_record_phdr (bfd *abfd,
+ unsigned long type,
+ bfd_boolean flags_valid,
+ flagword flags,
+ bfd_boolean at_valid,
+ bfd_vma at,
+ bfd_boolean includes_filehdr,
+ bfd_boolean includes_phdrs,
+ unsigned int count,
+ asection **secs)
+{
+ struct elf_segment_map *m, **pm;
+ bfd_size_type amt;
+
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ return TRUE;
+
+ amt = sizeof (struct elf_segment_map);
+ amt += ((bfd_size_type) count - 1) * sizeof (asection *);
+ m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ return FALSE;
+
+ 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_seg_map (abfd); *pm != NULL; pm = &(*pm)->next)
+ ;
+ *pm = m;
+
+ return TRUE;
+}
+
+#ifdef BFD64
+/* Return true iff this target is 32-bit. */
+
+static bfd_boolean
+is32bit (bfd *abfd)
+{
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+ {
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ return bed->s->elfclass == ELFCLASS32;
+ }
+
+ /* For non-ELF targets, use architecture information. */
+ return bfd_arch_bits_per_address (abfd) <= 32;
+}
+#endif
+
+/* bfd_sprintf_vma and bfd_fprintf_vma display an address in the
+ target's address size. */
+
+void
+bfd_sprintf_vma (bfd *abfd ATTRIBUTE_UNUSED, char *buf, bfd_vma value)
+{
+#ifdef BFD64
+ if (is32bit (abfd))
+ {
+ sprintf (buf, "%08lx", (unsigned long) value & 0xffffffff);
+ return;
+ }
+#endif
+ sprintf_vma (buf, value);
+}
+
+void
+bfd_fprintf_vma (bfd *abfd ATTRIBUTE_UNUSED, void *stream, bfd_vma value)
+{
+#ifdef BFD64
+ if (is32bit (abfd))
+ {
+ fprintf ((FILE *) stream, "%08lx", (unsigned long) value & 0xffffffff);
+ return;
+ }
+#endif
+ fprintf_vma ((FILE *) stream, value);
+}
+
+/*
+FUNCTION
+ bfd_alt_mach_code
+
+SYNOPSIS
+ bfd_boolean bfd_alt_mach_code (bfd *abfd, int alternative);
+
+DESCRIPTION
+
+ When more than one machine code number is available for the
+ same machine type, this function can be used to switch between
+ the preferred one (alternative == 0) and any others. Currently,
+ only ELF supports this feature, with up to two alternate
+ machine codes.
+*/
+
+bfd_boolean
+bfd_alt_mach_code (bfd *abfd, int alternative)
+{
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+ {
+ int code;
+
+ switch (alternative)
+ {
+ case 0:
+ code = get_elf_backend_data (abfd)->elf_machine_code;
+ break;
+
+ case 1:
+ code = get_elf_backend_data (abfd)->elf_machine_alt1;
+ if (code == 0)
+ return FALSE;
+ break;
+
+ case 2:
+ code = get_elf_backend_data (abfd)->elf_machine_alt2;
+ if (code == 0)
+ return FALSE;
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ elf_elfheader (abfd)->e_machine = code;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+FUNCTION
+ bfd_emul_get_maxpagesize
+
+SYNOPSIS
+ bfd_vma bfd_emul_get_maxpagesize (const char *);
+
+DESCRIPTION
+ Returns the maximum page size, in bytes, as determined by
+ emulation.
+
+RETURNS
+ Returns the maximum page size in bytes for ELF, 0 otherwise.
+*/
+
+bfd_vma
+bfd_emul_get_maxpagesize (const char *emul)
+{
+ const bfd_target *target;
+
+ target = bfd_find_target (emul, NULL);
+ if (target != NULL
+ && target->flavour == bfd_target_elf_flavour)
+ return xvec_get_elf_backend_data (target)->maxpagesize;
+
+ return 0;
+}
+
+static void
+bfd_elf_set_pagesize (const bfd_target *target, bfd_vma size,
+ int offset, const bfd_target *orig_target)
+{
+ if (target->flavour == bfd_target_elf_flavour)
+ {
+ const struct elf_backend_data *bed;
+
+ bed = xvec_get_elf_backend_data (target);
+ *((bfd_vma *) ((char *) bed + offset)) = size;
+ }
+
+ if (target->alternative_target
+ && target->alternative_target != orig_target)
+ bfd_elf_set_pagesize (target->alternative_target, size, offset,
+ orig_target);
+}
+
+/*
+FUNCTION
+ bfd_emul_set_maxpagesize
+
+SYNOPSIS
+ void bfd_emul_set_maxpagesize (const char *, bfd_vma);
+
+DESCRIPTION
+ For ELF, set the maximum page size for the emulation. It is
+ a no-op for other formats.
+
+*/
+
+void
+bfd_emul_set_maxpagesize (const char *emul, bfd_vma size)
+{
+ const bfd_target *target;
+
+ target = bfd_find_target (emul, NULL);
+ if (target)
+ bfd_elf_set_pagesize (target, size,
+ offsetof (struct elf_backend_data,
+ maxpagesize), target);
+}
+
+/*
+FUNCTION
+ bfd_emul_get_commonpagesize
+
+SYNOPSIS
+ bfd_vma bfd_emul_get_commonpagesize (const char *);
+
+DESCRIPTION
+ Returns the common page size, in bytes, as determined by
+ emulation.
+
+RETURNS
+ Returns the common page size in bytes for ELF, 0 otherwise.
+*/
+
+bfd_vma
+bfd_emul_get_commonpagesize (const char *emul)
+{
+ const bfd_target *target;
+
+ target = bfd_find_target (emul, NULL);
+ if (target != NULL
+ && target->flavour == bfd_target_elf_flavour)
+ return xvec_get_elf_backend_data (target)->commonpagesize;
+
+ return 0;
+}
+
+/*
+FUNCTION
+ bfd_emul_set_commonpagesize
+
+SYNOPSIS
+ void bfd_emul_set_commonpagesize (const char *, bfd_vma);
+
+DESCRIPTION
+ For ELF, set the common page size for the emulation. It is
+ a no-op for other formats.
+
+*/
+
+void
+bfd_emul_set_commonpagesize (const char *emul, bfd_vma size)
+{
+ const bfd_target *target;
+
+ target = bfd_find_target (emul, NULL);
+ if (target)
+ bfd_elf_set_pagesize (target, size,
+ offsetof (struct elf_backend_data,
+ commonpagesize), target);
+}
+
+/*
+FUNCTION
+ bfd_demangle
+
+SYNOPSIS
+ char *bfd_demangle (bfd *, const char *, int);
+
+DESCRIPTION
+ Wrapper around cplus_demangle. Strips leading underscores and
+ other such chars that would otherwise confuse the demangler.
+ If passed a g++ v3 ABI mangled name, returns a buffer allocated
+ with malloc holding the demangled name. Returns NULL otherwise
+ and on memory alloc failure.
+*/
+
+char *
+bfd_demangle (bfd *abfd, const char *name, int options)
+{
+ char *res, *alloc;
+ const char *pre, *suf;
+ size_t pre_len;
+ bfd_boolean skip_lead;
+
+ skip_lead = (abfd != NULL
+ && *name != '\0'
+ && bfd_get_symbol_leading_char (abfd) == *name);
+ if (skip_lead)
+ ++name;
+
+ /* This is a hack for better error reporting on XCOFF, PowerPC64-ELF
+ or the MS PE format. These formats have a number of leading '.'s
+ on at least some symbols, so we remove all dots to avoid
+ confusing the demangler. */
+ pre = name;
+ while (*name == '.' || *name == '$')
+ ++name;
+ pre_len = name - pre;
+
+ /* Strip off @plt and suchlike too. */
+ alloc = NULL;
+ suf = strchr (name, '@');
+ if (suf != NULL)
+ {
+ alloc = (char *) bfd_malloc (suf - name + 1);
+ if (alloc == NULL)
+ return NULL;
+ memcpy (alloc, name, suf - name);
+ alloc[suf - name] = '\0';
+ name = alloc;
+ }
+
+ res = cplus_demangle (name, options);
+
+ if (alloc != NULL)
+ free (alloc);
+
+ if (res == NULL)
+ {
+ if (skip_lead)
+ {
+ size_t len = strlen (pre) + 1;
+ alloc = (char *) bfd_malloc (len);
+ if (alloc == NULL)
+ return NULL;
+ memcpy (alloc, pre, len);
+ return alloc;
+ }
+ return NULL;
+ }
+
+ /* Put back any prefix or suffix. */
+ if (pre_len != 0 || suf != NULL)
+ {
+ size_t len;
+ size_t suf_len;
+ char *final;
+
+ len = strlen (res);
+ if (suf == NULL)
+ suf = res + len;
+ suf_len = strlen (suf) + 1;
+ final = (char *) bfd_malloc (pre_len + len + suf_len);
+ if (final != NULL)
+ {
+ memcpy (final, pre, pre_len);
+ memcpy (final + pre_len, res, len);
+ memcpy (final + pre_len + len, suf, suf_len);
+ }
+ free (res);
+ res = final;
+ }
+
+ return res;
+}
+
+/*
+FUNCTION
+ bfd_update_compression_header
+
+SYNOPSIS
+ void bfd_update_compression_header
+ (bfd *abfd, bfd_byte *contents, asection *sec);
+
+DESCRIPTION
+ Set the compression header at CONTENTS of SEC in ABFD and update
+ elf_section_flags for compression.
+*/
+
+void
+bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
+ asection *sec)
+{
+ if ((abfd->flags & BFD_COMPRESS) != 0)
+ {
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+ {
+ if ((abfd->flags & BFD_COMPRESS_GABI) != 0)
+ {
+ const struct elf_backend_data *bed
+ = get_elf_backend_data (abfd);
+
+ /* Set the SHF_COMPRESSED bit. */
+ elf_section_flags (sec) |= SHF_COMPRESSED;
+
+ if (bed->s->elfclass == ELFCLASS32)
+ {
+ Elf32_External_Chdr *echdr
+ = (Elf32_External_Chdr *) contents;
+ bfd_put_32 (abfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+ bfd_put_32 (abfd, sec->size, &echdr->ch_size);
+ bfd_put_32 (abfd, 1 << sec->alignment_power,
+ &echdr->ch_addralign);
+ }
+ else
+ {
+ Elf64_External_Chdr *echdr
+ = (Elf64_External_Chdr *) contents;
+ bfd_put_32 (abfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+ bfd_put_32 (abfd, 0, &echdr->ch_reserved);
+ bfd_put_64 (abfd, sec->size, &echdr->ch_size);
+ bfd_put_64 (abfd, 1 << sec->alignment_power,
+ &echdr->ch_addralign);
+ }
+ }
+ else
+ {
+ /* Clear the SHF_COMPRESSED bit. */
+ elf_section_flags (sec) &= ~SHF_COMPRESSED;
+
+ /* Write the zlib header. It should be "ZLIB" followed by
+ the uncompressed section size, 8 bytes in big-endian
+ order. */
+ memcpy (contents, "ZLIB", 4);
+ bfd_putb64 (sec->size, contents + 4);
+ }
+ }
+ }
+ else
+ abort ();
+}
+
+/*
+ FUNCTION
+ bfd_check_compression_header
+
+ SYNOPSIS
+ bfd_boolean bfd_check_compression_header
+ (bfd *abfd, bfd_byte *contents, asection *sec,
+ bfd_size_type *uncompressed_size);
+
+DESCRIPTION
+ Check the compression header at CONTENTS of SEC in ABFD and
+ store the uncompressed size in UNCOMPRESSED_SIZE if the
+ compression header is valid.
+
+RETURNS
+ Return TRUE if the compression header is valid.
+*/
+
+bfd_boolean
+bfd_check_compression_header (bfd *abfd, bfd_byte *contents,
+ asection *sec,
+ bfd_size_type *uncompressed_size)
+{
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && (elf_section_flags (sec) & SHF_COMPRESSED) != 0)
+ {
+ Elf_Internal_Chdr chdr;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ if (bed->s->elfclass == ELFCLASS32)
+ {
+ Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) contents;
+ chdr.ch_type = bfd_get_32 (abfd, &echdr->ch_type);
+ chdr.ch_size = bfd_get_32 (abfd, &echdr->ch_size);
+ chdr.ch_addralign = bfd_get_32 (abfd, &echdr->ch_addralign);
+ }
+ else
+ {
+ Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) contents;
+ chdr.ch_type = bfd_get_32 (abfd, &echdr->ch_type);
+ chdr.ch_size = bfd_get_64 (abfd, &echdr->ch_size);
+ chdr.ch_addralign = bfd_get_64 (abfd, &echdr->ch_addralign);
+ }
+ if (chdr.ch_type == ELFCOMPRESS_ZLIB
+ && chdr.ch_addralign == 1U << sec->alignment_power)
+ {
+ *uncompressed_size = chdr.ch_size;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+FUNCTION
+ bfd_get_compression_header_size
+
+SYNOPSIS
+ int bfd_get_compression_header_size (bfd *abfd, asection *sec);
+
+DESCRIPTION
+ Return the size of the compression header of SEC in ABFD.
+
+RETURNS
+ Return the size of the compression header in bytes.
+*/
+
+int
+bfd_get_compression_header_size (bfd *abfd, asection *sec)
+{
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+ {
+ if (sec == NULL)
+ {
+ if (!(abfd->flags & BFD_COMPRESS_GABI))
+ return 0;
+ }
+ else if (!(elf_section_flags (sec) & SHF_COMPRESSED))
+ return 0;
+
+ if (get_elf_backend_data (abfd)->s->elfclass == ELFCLASS32)
+ return sizeof (Elf32_External_Chdr);
+ else
+ return sizeof (Elf64_External_Chdr);
+ }
+
+ return 0;
+}
+
+/*
+FUNCTION
+ bfd_convert_section_size
+
+SYNOPSIS
+ bfd_size_type bfd_convert_section_size
+ (bfd *ibfd, asection *isec, bfd *obfd, bfd_size_type size);
+
+DESCRIPTION
+ Convert the size @var{size} of the section @var{isec} in input
+ BFD @var{ibfd} to the section size in output BFD @var{obfd}.
+*/
+
+bfd_size_type
+bfd_convert_section_size (bfd *ibfd, sec_ptr isec, bfd *obfd,
+ bfd_size_type size)
+{
+ bfd_size_type hdr_size;
+
+ /* Do nothing if input file will be decompressed. */
+ if ((ibfd->flags & BFD_DECOMPRESS))
+ return size;
+
+ /* Do nothing if either input or output aren't ELF. */
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ return size;
+
+ /* Do nothing if ELF classes of input and output are the same. */
+ if (get_elf_backend_data (ibfd)->s->elfclass
+ == get_elf_backend_data (obfd)->s->elfclass)
+ return size;
+
+ /* Do nothing if the input section isn't a SHF_COMPRESSED section. */
+ hdr_size = bfd_get_compression_header_size (ibfd, isec);
+ if (hdr_size == 0)
+ return size;
+
+ /* Adjust the size of the output SHF_COMPRESSED section. */
+ if (hdr_size == sizeof (Elf32_External_Chdr))
+ return (size - sizeof (Elf32_External_Chdr)
+ + sizeof (Elf64_External_Chdr));
+ else
+ return (size - sizeof (Elf64_External_Chdr)
+ + sizeof (Elf32_External_Chdr));
+}
+
+/*
+FUNCTION
+ bfd_convert_section_contents
+
+SYNOPSIS
+ bfd_boolean bfd_convert_section_contents
+ (bfd *ibfd, asection *isec, bfd *obfd,
+ bfd_byte **ptr, bfd_size_type *ptr_size);
+
+DESCRIPTION
+ Convert the contents, stored in @var{*ptr}, of the section
+ @var{isec} in input BFD @var{ibfd} to output BFD @var{obfd}
+ if needed. The original buffer pointed to by @var{*ptr} may
+ be freed and @var{*ptr} is returned with memory malloc'd by this
+ function, and the new size written to @var{ptr_size}.
+*/
+
+bfd_boolean
+bfd_convert_section_contents (bfd *ibfd, sec_ptr isec, bfd *obfd,
+ bfd_byte **ptr, bfd_size_type *ptr_size)
+{
+ bfd_byte *contents;
+ bfd_size_type ihdr_size, ohdr_size, size;
+ Elf_Internal_Chdr chdr;
+ bfd_boolean use_memmove;
+
+ /* Do nothing if input file will be decompressed. */
+ if ((ibfd->flags & BFD_DECOMPRESS))
+ return TRUE;
+
+ /* Do nothing if either input or output aren't ELF. */
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ return TRUE;
+
+ /* Do nothing if ELF classes of input and output are the same. */
+ if (get_elf_backend_data (ibfd)->s->elfclass
+ == get_elf_backend_data (obfd)->s->elfclass)
+ return TRUE;
+
+ /* Do nothing if the input section isn't a SHF_COMPRESSED section. */
+ ihdr_size = bfd_get_compression_header_size (ibfd, isec);
+ if (ihdr_size == 0)
+ return TRUE;
+
+ contents = *ptr;
+
+ /* Convert the contents of the input SHF_COMPRESSED section to
+ output. Get the input compression header and the size of the
+ output compression header. */
+ if (ihdr_size == sizeof (Elf32_External_Chdr))
+ {
+ Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) contents;
+ chdr.ch_type = bfd_get_32 (ibfd, &echdr->ch_type);
+ chdr.ch_size = bfd_get_32 (ibfd, &echdr->ch_size);
+ chdr.ch_addralign = bfd_get_32 (ibfd, &echdr->ch_addralign);
+
+ ohdr_size = sizeof (Elf64_External_Chdr);
+
+ use_memmove = FALSE;
+ }
+ else
+ {
+ Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) contents;
+ chdr.ch_type = bfd_get_32 (ibfd, &echdr->ch_type);
+ chdr.ch_size = bfd_get_64 (ibfd, &echdr->ch_size);
+ chdr.ch_addralign = bfd_get_64 (ibfd, &echdr->ch_addralign);
+
+ ohdr_size = sizeof (Elf32_External_Chdr);
+ use_memmove = TRUE;
+ }
+
+ size = bfd_get_section_size (isec) - ihdr_size + ohdr_size;
+ if (!use_memmove)
+ {
+ contents = (bfd_byte *) bfd_malloc (size);
+ if (contents == NULL)
+ return FALSE;
+ }
+
+ /* Write out the output compression header. */
+ if (ohdr_size == sizeof (Elf32_External_Chdr))
+ {
+ Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) contents;
+ bfd_put_32 (obfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+ bfd_put_32 (obfd, chdr.ch_size, &echdr->ch_size);
+ bfd_put_32 (obfd, chdr.ch_addralign, &echdr->ch_addralign);
+ }
+ else
+ {
+ Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) contents;
+ bfd_put_32 (obfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+ bfd_put_32 (obfd, 0, &echdr->ch_reserved);
+ bfd_put_64 (obfd, chdr.ch_size, &echdr->ch_size);
+ bfd_put_64 (obfd, chdr.ch_addralign, &echdr->ch_addralign);
+ }
+
+ /* Copy the compressed contents. */
+ if (use_memmove)
+ memmove (contents + ohdr_size, *ptr + ihdr_size, size - ohdr_size);
+ else
+ {
+ memcpy (contents + ohdr_size, *ptr + ihdr_size, size - ohdr_size);
+ free (*ptr);
+ *ptr = contents;
+ }
+
+ *ptr_size = size;
+ return TRUE;
+}