summaryrefslogtreecommitdiff
path: root/bfd/merge.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/merge.c')
-rw-r--r--bfd/merge.c76
1 files changed, 66 insertions, 10 deletions
diff --git a/bfd/merge.c b/bfd/merge.c
index 5f45ba6e106..b77a3468f8a 100644
--- a/bfd/merge.c
+++ b/bfd/merge.c
@@ -25,6 +25,7 @@
#include "sysdep.h"
#include "bfd.h"
+#include "elf-bfd.h"
#include "libbfd.h"
#include "hashtab.h"
#include "libiberty.h"
@@ -283,13 +284,15 @@ sec_merge_add (struct sec_merge_hash *tab, const char *str,
}
static bfd_boolean
-sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
+sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry,
+ file_ptr offset)
{
struct sec_merge_sec_info *secinfo = entry->secinfo;
asection *sec = secinfo->sec;
char *pad = NULL;
bfd_size_type off = 0;
int alignment_power = sec->output_section->alignment_power;
+ unsigned char *contents = NULL;
if (alignment_power)
{
@@ -298,6 +301,14 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
return FALSE;
}
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+ {
+ Elf_Internal_Shdr *hdr
+ = &elf_section_data (sec->output_section)->this_hdr;
+ if (hdr->sh_offset == (file_ptr) -1)
+ contents = hdr->contents;
+ }
+
for (; entry != NULL && entry->secinfo == secinfo; entry = entry->next)
{
const char *str;
@@ -306,7 +317,12 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
len = -off & (entry->alignment - 1);
if (len != 0)
{
- if (bfd_bwrite (pad, len, abfd) != len)
+ if (contents)
+ {
+ memcpy (contents + offset, pad, len);
+ offset += len;
+ }
+ else if (bfd_bwrite (pad, len, abfd) != len)
goto err;
off += len;
}
@@ -314,7 +330,12 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
str = entry->root.string;
len = entry->len;
- if (bfd_bwrite (str, len, abfd) != len)
+ if (contents)
+ {
+ memcpy (contents + offset, str, len);
+ offset += len;
+ }
+ else if (bfd_bwrite (str, len, abfd) != len)
goto err;
off += len;
@@ -322,9 +343,13 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
/* Trailing alignment needed? */
off = sec->size - off;
- if (off != 0
- && bfd_bwrite (pad, off, abfd) != off)
- goto err;
+ if (off != 0)
+ {
+ if (contents)
+ memcpy (contents + offset, pad, off);
+ else if (bfd_bwrite (pad, off, abfd) != off)
+ goto err;
+ }
if (pad != NULL)
free (pad);
@@ -785,6 +810,7 @@ _bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo)
{
struct sec_merge_sec_info *secinfo;
file_ptr pos;
+ unsigned char *contents;
secinfo = (struct sec_merge_sec_info *) psecinfo;
@@ -794,12 +820,42 @@ _bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo)
if (secinfo->first_str == NULL)
return TRUE;
+ contents = NULL;
+
/* FIXME: octets_per_byte. */
- pos = sec->output_section->filepos + sec->output_offset;
- if (bfd_seek (output_bfd, pos, SEEK_SET) != 0)
- return FALSE;
+ if (bfd_get_flavour (output_bfd) == bfd_target_elf_flavour)
+ {
+ Elf_Internal_Shdr *hdr
+ = &elf_section_data (sec->output_section)->this_hdr;
+ if (hdr->sh_offset == (file_ptr) -1)
+ {
+ if ((sec->output_section->flags & SEC_ELF_COMPRESS) == 0)
+ abort ();
+
+ /* Cache the section contents so that they can be compressed
+ later. */
+ contents = hdr->contents;
+ if (contents == NULL)
+ {
+ /* Use bfd_malloc since it will be freed by
+ bfd_compress_section_contents. */
+ contents = (unsigned char *) bfd_malloc (hdr->sh_size);
+ if (contents == NULL)
+ return FALSE;
+ hdr->contents = contents;
+ }
+ }
+ }
+
+ if (contents == NULL)
+ {
+ pos = sec->output_section->filepos + sec->output_offset;
+ if (bfd_seek (output_bfd, pos, SEEK_SET) != 0)
+ return FALSE;
+ }
- if (! sec_merge_emit (output_bfd, secinfo->first_str))
+ if (! sec_merge_emit (output_bfd, secinfo->first_str,
+ sec->output_offset))
return FALSE;
return TRUE;