* merge.c (struct sec_merge_hash_entry): Add alignment field.

(struct sec_merge_hash): Remove alignment_power.
	(sec_merge_hash_newfunc): Clear alignment.
	(sec_merge_hash_lookup): Pass alignment as argument.
	Use hashp->root.next, not hashp->next to walk the hash chain.
	If a string already in the hashtable does not have required
	alignment, create a new hashtable entry.
	(sec_merge_init): Remove alignment_power argument.
	(sec_merge_add): Add alignment argument.
	(sec_merge_emit): Alignment is now a per-entity thing, not per
	section.
	(_bfd_merge_section): Sanity check even non-SEC_STRINGS sections
	for proper alignment.
	Pass alignment information to sec_merge_add.
This commit is contained in:
Jakub Jelinek 2001-04-24 17:55:57 +00:00
parent 851c18e0e9
commit a531bbd206
2 changed files with 82 additions and 47 deletions

View File

@ -1,3 +1,20 @@
2001-04-24 Jakub Jelinek <jakub@redhat.com>
* merge.c (struct sec_merge_hash_entry): Add alignment field.
(struct sec_merge_hash): Remove alignment_power.
(sec_merge_hash_newfunc): Clear alignment.
(sec_merge_hash_lookup): Pass alignment as argument.
Use hashp->root.next, not hashp->next to walk the hash chain.
If a string already in the hashtable does not have required
alignment, create a new hashtable entry.
(sec_merge_init): Remove alignment_power argument.
(sec_merge_add): Add alignment argument.
(sec_merge_emit): Alignment is now a per-entity thing, not per
section.
(_bfd_merge_section): Sanity check even non-SEC_STRINGS sections
for proper alignment.
Pass alignment information to sec_merge_add.
2001-04-24 Christian Groessler <cpg@aladdin.de>
* coff-z8k.c (extra_case): added handler for R_DISP7, R_CALLR

View File

@ -34,6 +34,9 @@ struct sec_merge_hash_entry
struct bfd_hash_entry root;
/* Length of this entry. */
unsigned int len;
/* Start of this string needs to be aligned to
alignment octets (not 1 << align). */
unsigned int alignment;
/* Index within the merged section. */
bfd_size_type index;
/* Which section is it in. */
@ -55,9 +58,6 @@ struct sec_merge_hash
struct sec_merge_hash_entry *last;
/* Entity size. */
unsigned int entsize;
/* Start of each string needs to be aligned to 1 << alignment_power
octets. */
unsigned int alignment_power;
/* Are entries fixed size or zero terminated strings? */
boolean strings;
};
@ -85,13 +85,13 @@ struct sec_merge_sec_info
static struct bfd_hash_entry *sec_merge_hash_newfunc
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
static struct sec_merge_hash_entry *sec_merge_hash_lookup
PARAMS ((struct sec_merge_hash *, const char *, boolean));
PARAMS ((struct sec_merge_hash *, const char *, unsigned int, boolean));
static struct sec_merge_hash *sec_merge_init
PARAMS ((unsigned int, unsigned int, boolean));
PARAMS ((unsigned int, boolean));
static struct sec_merge_hash_entry *sec_merge_add
PARAMS ((struct sec_merge_hash *, const char *));
PARAMS ((struct sec_merge_hash *, const char *, unsigned int));
static boolean sec_merge_emit
PARAMS ((bfd *, struct sec_merge_hash *, struct sec_merge_hash_entry *));
PARAMS ((bfd *, struct sec_merge_hash_entry *));
/* Routine to create an entry in a section merge hashtab. */
@ -119,6 +119,7 @@ sec_merge_hash_newfunc (entry, table, string)
{
/* Initialize the local fields. */
ret->index = (bfd_size_type) -1;
ret->alignment = 0;
ret->sec = NULL;
ret->next = NULL;
}
@ -129,9 +130,10 @@ sec_merge_hash_newfunc (entry, table, string)
/* Look up an entry in a section merge hash table. */
static struct sec_merge_hash_entry *
sec_merge_hash_lookup (table, string, create)
sec_merge_hash_lookup (table, string, alignment, create)
struct sec_merge_hash *table;
const char *string;
unsigned int alignment;
boolean create;
{
register const unsigned char *s;
@ -193,13 +195,21 @@ sec_merge_hash_lookup (table, string, create)
index = hash % table->table.size;
for (hashp = (struct sec_merge_hash_entry *) table->table.table[index];
hashp != (struct sec_merge_hash_entry *) NULL;
hashp = (struct sec_merge_hash_entry *) hashp->next)
hashp = (struct sec_merge_hash_entry *) hashp->root.next)
{
if (hashp->root.hash == hash
&& len == hashp->len
&& memcmp (hashp->root.string, string, len) == 0)
{
/* If the string we found does not have at least the required
alignment, we need to insert another copy.
FIXME: The old copy could be removed and the space allocated
for it filled by some new string (similarly with padding). */
if (hashp->alignment < alignment)
break;
return hashp;
}
}
if (! create)
return (struct sec_merge_hash_entry *) NULL;
@ -212,6 +222,7 @@ sec_merge_hash_lookup (table, string, create)
hashp->root.string = string;
hashp->root.hash = hash;
hashp->len = len;
hashp->alignment = alignment;
hashp->root.next = table->table.table[index];
table->table.table[index] = (struct bfd_hash_entry *) hashp;
@ -221,8 +232,8 @@ sec_merge_hash_lookup (table, string, create)
/* Create a new hash table. */
static struct sec_merge_hash *
sec_merge_init (alignment_power, entsize, strings)
unsigned int alignment_power, entsize;
sec_merge_init (entsize, strings)
unsigned int entsize;
boolean strings;
{
struct sec_merge_hash *table;
@ -241,7 +252,6 @@ sec_merge_init (alignment_power, entsize, strings)
table->size = 0;
table->first = NULL;
table->last = NULL;
table->alignment_power = alignment_power;
table->entsize = entsize;
table->strings = strings;
@ -252,21 +262,22 @@ sec_merge_init (alignment_power, entsize, strings)
already present. */
static struct sec_merge_hash_entry *
sec_merge_add (tab, str)
sec_merge_add (tab, str, alignment)
struct sec_merge_hash *tab;
const char *str;
unsigned int alignment;
{
register struct sec_merge_hash_entry *entry;
entry = sec_merge_hash_lookup (tab, str, true);
entry = sec_merge_hash_lookup (tab, str, alignment, true);
if (entry == NULL)
return NULL;
if (entry->index == (bfd_size_type) -1)
{
tab->size = (tab->size + alignment - 1) & ~((bfd_vma) alignment - 1);
entry->index = tab->size;
tab->size += entry->len;
tab->size = align_power (tab->size, tab->alignment_power);
if (tab->first == NULL)
tab->first = entry;
else
@ -278,39 +289,42 @@ sec_merge_add (tab, str)
}
static boolean
sec_merge_emit (abfd, tab, entry)
sec_merge_emit (abfd, entry)
register bfd *abfd;
struct sec_merge_hash *tab;
struct sec_merge_hash_entry *entry;
{
asection *sec = entry->sec;
char *pad = "";
bfd_size_type off = 0;
int alignment_power = bfd_get_section_alignment (abfd, sec->output_section);
if (tab->alignment_power)
pad = bfd_zmalloc (1 << tab->alignment_power);
if (alignment_power)
pad = bfd_zmalloc (1 << alignment_power);
for (; entry != NULL && entry->sec == sec; entry = entry->next)
{
register const char *str;
register size_t len;
len = off & (entry->alignment - 1);
if (len)
{
len = entry->alignment - len;
if (bfd_write ((PTR) pad, 1, len, abfd) != len)
break;
off += len;
}
str = entry->root.string;
len = entry->len;
if (bfd_write ((PTR) str, 1, len, abfd) != len)
break;
if (tab->alignment_power)
{
len &= (1 << tab->alignment_power) - 1;
if (len && bfd_write ((PTR) pad, 1,
(1 << tab->alignment_power) - len,
abfd) != (1 << tab->alignment_power) - len)
break;
}
off += len;
}
if (tab->alignment_power)
if (alignment_power)
free (pad);
return entry == NULL || entry->sec != sec;
@ -330,7 +344,7 @@ _bfd_merge_section (abfd, psinfo, sec, psecinfo)
struct sec_merge_info *sinfo;
struct sec_merge_sec_info *secinfo;
unsigned char *p, *end;
bfd_vma mask;
bfd_vma mask, eltalign;
unsigned int align;
unsigned int i;
@ -354,16 +368,18 @@ _bfd_merge_section (abfd, psinfo, sec, psecinfo)
}
align = bfd_get_section_alignment (abfd, sec);
if ((sec->flags & SEC_STRINGS)
&& ((sec->entsize < (unsigned int)(1 << align)
&& (sec->entsize & (sec->entsize - 1)))
if ((sec->entsize < (unsigned int)(1 << align)
&& ((sec->entsize & (sec->entsize - 1))
|| !(sec->flags & SEC_STRINGS)))
|| (sec->entsize > (unsigned int)(1 << align)
&& (sec->entsize & ((1 << align) - 1)))))
&& (sec->entsize & ((1 << align) - 1))))
{
/* Sanity check. If string character size is smaller than
alignment, then we require character size to be a power
of 2, otherwise character size must be integer multiple
of alignment. */
of alignment. For non-string constants, alignment must
be smaller than or equal to entity size and entity size
must be integer multiple of alignment. */
return true;
}
@ -372,8 +388,7 @@ _bfd_merge_section (abfd, psinfo, sec, psecinfo)
for (sinfo = (struct sec_merge_info *) *psinfo; sinfo; sinfo = sinfo->next)
if (! ((sinfo->last->flags ^ sec->flags) & (SEC_MERGE | SEC_STRINGS))
&& sinfo->last->entsize == sec->entsize
&& ! strcmp (sinfo->last->name, sec->name)
&& bfd_get_section_alignment (abfd, sinfo->last) == align)
&& ! strcmp (sinfo->last->name, sec->name))
break;
if (sinfo == NULL)
@ -387,8 +402,7 @@ _bfd_merge_section (abfd, psinfo, sec, psecinfo)
sinfo->next = (struct sec_merge_info *) *psinfo;
*psinfo = (PTR) sinfo;
sinfo->htab =
sec_merge_init ((sec->flags & SEC_STRINGS) ? align : 0,
sec->entsize, (sec->flags & SEC_STRINGS));
sec_merge_init (sec->entsize, (sec->flags & SEC_STRINGS));
if (sinfo->htab == NULL)
goto error_return;
}
@ -411,14 +425,18 @@ _bfd_merge_section (abfd, psinfo, sec, psecinfo)
end = secinfo->contents + sec->_raw_size;
nul = false;
mask = ((bfd_vma)1 << sinfo->htab->alignment_power) - 1;
mask = ((bfd_vma)1 << align) - 1;
if (sec->flags & SEC_STRINGS)
{
for (p = secinfo->contents; p < end;)
{
struct sec_merge_hash_entry *entry;
entry = sec_merge_add (sinfo->htab, p);
eltalign = p - secinfo->contents;
eltalign = ((eltalign ^ (eltalign - 1)) + 1) >> 1;
if (!eltalign || eltalign > mask)
eltalign = mask + 1;
entry = sec_merge_add (sinfo->htab, p, eltalign);
if (entry->sec == NULL)
{
if (secinfo->first == NULL)
@ -433,7 +451,7 @@ _bfd_merge_section (abfd, psinfo, sec, psecinfo)
if (!nul && !((p - secinfo->contents) & mask))
{
nul = true;
entry = sec_merge_add (sinfo->htab, "");
entry = sec_merge_add (sinfo->htab, "", mask + 1);
if (entry->sec == NULL)
{
if (secinfo->first == NULL)
@ -456,7 +474,7 @@ _bfd_merge_section (abfd, psinfo, sec, psecinfo)
if (!nul && !((p - secinfo->contents) & mask))
{
nul = true;
entry = sec_merge_add (sinfo->htab, p);
entry = sec_merge_add (sinfo->htab, p, mask + 1);
if (entry->sec == NULL)
{
if (secinfo->first == NULL)
@ -475,7 +493,7 @@ _bfd_merge_section (abfd, psinfo, sec, psecinfo)
{
struct sec_merge_hash_entry *entry;
entry = sec_merge_add (sinfo->htab, p);
entry = sec_merge_add (sinfo->htab, p, 1);
if (entry->sec == NULL)
{
if (secinfo->first == NULL)
@ -518,7 +536,7 @@ _bfd_write_merged_section (output_bfd, sec, psecinfo)
SEEK_SET) != 0)
return false;
if (! sec_merge_emit (output_bfd, secinfo->htab, secinfo->first))
if (! sec_merge_emit (output_bfd, secinfo->first))
return false;
return true;
@ -584,7 +602,7 @@ _bfd_merged_section_offset (output_bfd, psec, psecinfo, offset, addend)
p = secinfo->contents
+ ((offset + addend) / sec->entsize) * sec->entsize;
}
entry = sec_merge_hash_lookup (secinfo->htab, p, false);
entry = sec_merge_hash_lookup (secinfo->htab, p, 0, false);
if (!entry)
{
if (! secinfo->htab->strings)