Add support for changing LMA and VMA of sections/

This commit is contained in:
Nick Clifton 1998-07-02 00:06:49 +00:00
parent 6de2add29f
commit 9e7e5d5e5b
2 changed files with 346 additions and 101 deletions

View File

@ -1,3 +1,8 @@
Wed Jul 1 17:05:53 1998 Nick Clifton <nickc@cygnus.com>
* elf.c (copy_private_bfd_data): Add support for changing VMA or
LMA of sections.
Wed Jul 1 16:58:50 1998 Ian Lance Taylor <ian@cygnus.com>
* coff-sh.c (sh_relax_delete_bytes): Correct address comparisons

442
bfd/elf.c
View File

@ -445,7 +445,8 @@ bfd_elf_find_section (abfd, name)
i_shdrp = elf_elfsections (abfd);
if (i_shdrp != NULL)
{
shstrtab = bfd_elf_get_str_section (abfd, elf_elfheader (abfd)->e_shstrndx);
shstrtab = bfd_elf_get_str_section
(abfd, elf_elfheader (abfd)->e_shstrndx);
if (shstrtab != NULL)
{
max = elf_elfheader (abfd)->e_shnum;
@ -1841,7 +1842,7 @@ elf_map_symbols (abfd)
num_sections++;
#ifdef DEBUG
fprintf (stderr,
_("creating section symbol, name = %s, value = 0x%.8lx, index = %d, section = 0x%.8lx\n"),
_("creating section symbol, name = %s, value = 0x%.8lx, index = %d, section = 0x%.8lx\n"),
asect->name, (long) asect->vma, asect->index, (long) asect);
#endif
}
@ -2087,7 +2088,7 @@ map_sections_to_segments (abfd)
unsigned int phdr_index;
bfd_vma maxpagesize;
asection **hdrpp;
boolean phdr_in_section = true;
boolean phdr_in_segment = true;
boolean writable;
asection *dynsec;
@ -2182,7 +2183,7 @@ map_sections_to_segments (abfd)
if ((abfd->flags & D_PAGED) == 0
|| sections[0]->lma < phdr_size
|| sections[0]->lma % maxpagesize < phdr_size % maxpagesize)
phdr_in_section = false;
phdr_in_segment = false;
}
for (i = 0, hdrpp = sections; i < count; i++, hdrpp++)
@ -2260,7 +2261,7 @@ map_sections_to_segments (abfd)
/* We need a new program segment. We must create a new program
header holding all the sections from phdr_index until hdr. */
m = make_mapping (abfd, sections, phdr_index, i, phdr_in_section);
m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
if (m == NULL)
goto error_return;
@ -2274,13 +2275,13 @@ map_sections_to_segments (abfd)
last_hdr = hdr;
phdr_index = i;
phdr_in_section = false;
phdr_in_segment = false;
}
/* Create a final PT_LOAD program segment. */
if (last_hdr != NULL)
{
m = make_mapping (abfd, sections, phdr_index, i, phdr_in_section);
m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
if (m == NULL)
goto error_return;
@ -2340,7 +2341,7 @@ map_sections_to_segments (abfd)
return false;
}
/* Sort sections by VMA. */
/* Sort sections by address. */
static int
elf_sort_sections (arg1, arg2)
@ -2357,8 +2358,8 @@ elf_sort_sections (arg1, arg2)
else if (sec1->lma > sec2->lma)
return 1;
/* Sort by VMA. Normally the LMA and the VMA will be the same, and
this will do nothing. */
/* Then sort by VMA. Normally the LMA and the VMA will be
the same, and this will do nothing. */
if (sec1->vma < sec2->vma)
return -1;
else if (sec1->vma > sec2->vma)
@ -2461,6 +2462,7 @@ assign_file_positions_for_segments (abfd)
filehdr_paddr = 0;
phdrs_vaddr = 0;
phdrs_paddr = 0;
for (m = elf_tdata (abfd)->segment_map, p = phdrs;
m != NULL;
m = m->next, p++)
@ -2515,7 +2517,7 @@ assign_file_positions_for_segments (abfd)
p->p_offset = 0;
p->p_filesz = 0;
p->p_memsz = 0;
if (m->includes_filehdr)
{
if (! m->p_flags_valid)
@ -2550,6 +2552,7 @@ assign_file_positions_for_segments (abfd)
{
if (! m->p_flags_valid)
p->p_flags |= PF_R;
if (m->includes_filehdr)
{
if (p->p_type == PT_LOAD)
@ -2561,6 +2564,7 @@ assign_file_positions_for_segments (abfd)
else
{
p->p_offset = bed->s->sizeof_ehdr;
if (m->count > 0)
{
BFD_ASSERT (p->p_type == PT_LOAD);
@ -2568,12 +2572,16 @@ assign_file_positions_for_segments (abfd)
if (! m->p_paddr_valid)
p->p_paddr -= off - p->p_offset;
}
if (p->p_type == PT_LOAD)
{
phdrs_vaddr = p->p_vaddr;
phdrs_paddr = p->p_paddr;
}
else
phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr;
}
p->p_filesz += alloc * bed->s->sizeof_phdr;
p->p_memsz += alloc * bed->s->sizeof_phdr;
}
@ -2593,6 +2601,7 @@ assign_file_positions_for_segments (abfd)
}
voff = off;
for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
{
asection *sec;
@ -2619,10 +2628,14 @@ assign_file_positions_for_segments (abfd)
if (p->p_type == PT_LOAD)
{
bfd_vma adjust;
bfd_signed_vma adjust;
if ((flags & SEC_LOAD) != 0)
adjust = sec->lma - (p->p_paddr + p->p_memsz);
{
adjust = sec->lma - (p->p_paddr + p->p_memsz);
if (adjust < 0)
adjust = 0;
}
else if ((flags & SEC_ALLOC) != 0)
{
/* The section VMA must equal the file position
@ -2641,7 +2654,16 @@ assign_file_positions_for_segments (abfd)
if (adjust != 0)
{
if (i == 0)
abort ();
{
(* _bfd_error_handler)
(_("Error: First section in segment (%s) starts at 0x%x"),
bfd_section_name (abfd, sec), sec->lma);
(* _bfd_error_handler)
(_(" whereas segment starts at 0x%x"),
p->p_paddr);
return false;
}
p->p_memsz += adjust;
off += adjust;
voff += adjust;
@ -2658,6 +2680,7 @@ assign_file_positions_for_segments (abfd)
if ((flags & SEC_LOAD) != 0
|| (flags & SEC_HAS_CONTENTS) != 0)
off += sec->_raw_size;
if ((flags & SEC_ALLOC) != 0)
voff += sec->_raw_size;
}
@ -2920,7 +2943,7 @@ prep_headers (abfd)
bfd *abfd;
{
Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */
Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */
Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */
Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */
int count;
struct bfd_strtab_hash *shstrtab;
@ -3110,8 +3133,8 @@ _bfd_elf_write_object_contents (abfd)
unsigned int count;
if (! abfd->output_has_begun
&& ! _bfd_elf_compute_section_file_positions (abfd,
(struct bfd_link_info *) NULL))
&& ! _bfd_elf_compute_section_file_positions
(abfd, (struct bfd_link_info *) NULL))
return false;
i_shdrp = elf_elfsections (abfd);
@ -3121,6 +3144,7 @@ _bfd_elf_write_object_contents (abfd)
bfd_map_over_sections (abfd, bed->s->write_relocs, &failed);
if (failed)
return false;
_bfd_elf_assign_file_positions_for_relocs (abfd);
/* After writing the headers, we need to write the sections too... */
@ -3264,8 +3288,10 @@ copy_private_bfd_data (ibfd, obfd)
struct elf_segment_map **pm;
struct elf_segment_map *m;
Elf_Internal_Phdr *p;
unsigned int i, c;
unsigned int i;
unsigned int num_segments;
unsigned int phdr_included = false;
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour)
return true;
@ -3278,33 +3304,54 @@ copy_private_bfd_data (ibfd, obfd)
mfirst = NULL;
pm = &mfirst;
c = elf_elfheader (ibfd)->e_phnum;
for (i = 0, p = elf_tdata (ibfd)->phdr; i < c; i++, p++)
num_segments = elf_elfheader (ibfd)->e_phnum;
#define IS_CONTAINED_BY(addr, len, bottom, phdr) \
((addr) >= (bottom) \
&& ( ((addr) + (len)) <= ((bottom) + (phdr)->p_memsz) \
|| ((addr) + (len)) <= ((bottom) + (phdr)->p_filesz)))
/* The complicated case when p_vaddr is 0 is to handle the Solaris
linker, which generates a PT_INTERP section with p_vaddr and
p_memsz set to 0. */
#define IS_SOLARIS_PT_INTERP(p, s) \
(p->p_vaddr == 0 \
&& p->p_filesz > 0 \
&& (s->flags & SEC_HAS_CONTENTS) != 0 \
&& s->_raw_size > 0 \
&& (bfd_vma) s->filepos >= p->p_offset \
&& ((bfd_vma) s->filepos + s->_raw_size \
<= p->p_offset + p->p_filesz))
/* Scan through the segments specified in the program header
of the input BFD. */
for (i = 0, p = elf_tdata (ibfd)->phdr; i < num_segments; i++, p++)
{
unsigned int csecs;
asection *s;
asection **sections;
asection *os;
unsigned int isec;
bfd_vma matching_lma;
bfd_vma suggested_lma;
unsigned int j;
/* For each section in the input BFD, decide if it should be included
in the current segment. A section will be included if it is within
the address space of the segment, and it is an allocated segment,
and there is an output section associated with it. */
csecs = 0;
/* The complicated case when p_vaddr is 0 is to handle the
Solaris linker, which generates a PT_INTERP section with
p_vaddr and p_memsz set to 0. */
for (s = ibfd->sections; s != NULL; s = s->next)
if (((s->vma >= p->p_vaddr
&& (s->vma + s->_raw_size <= p->p_vaddr + p->p_memsz
|| s->vma + s->_raw_size <= p->p_vaddr + p->p_filesz))
|| (p->p_vaddr == 0
&& p->p_filesz > 0
&& (s->flags & SEC_HAS_CONTENTS) != 0
&& s->_raw_size > 0
&& (bfd_vma) s->filepos >= p->p_offset
&& ((bfd_vma) s->filepos + s->_raw_size
<= p->p_offset + p->p_filesz)))
if ((IS_CONTAINED_BY (s->vma, s->_raw_size, p->p_vaddr, p)
|| IS_SOLARIS_PT_INTERP (p, s))
&& (s->flags & SEC_ALLOC) != 0
&& s->output_section != NULL)
++csecs;
/* Allocate a segment map big enough to contain all of the
sections we have selected. */
m = ((struct elf_segment_map *)
bfd_alloc (obfd,
(sizeof (struct elf_segment_map)
@ -3312,49 +3359,101 @@ copy_private_bfd_data (ibfd, obfd)
if (m == NULL)
return false;
m->next = NULL;
m->p_type = p->p_type;
m->p_flags = p->p_flags;
/* Initialise the fields of the segment map. Default to
using the physical address of the segment in the input BFD. */
m->next = NULL;
m->p_type = p->p_type;
m->p_flags = p->p_flags;
m->p_flags_valid = 1;
/* Default to using the physical address of the segment
in the input BFD. */
m->p_paddr = p->p_paddr;
m->p_paddr = p->p_paddr;
m->p_paddr_valid = 1;
/* Determine if this segment contains the ELF file header
and if it contains the program headers themselves. */
m->includes_filehdr = (p->p_offset == 0
&& p->p_filesz >= iehdr->e_ehsize);
m->includes_phdrs = (p->p_offset <= (bfd_vma) iehdr->e_phoff
&& (p->p_offset + p->p_filesz
>= ((bfd_vma) iehdr->e_phoff
+ iehdr->e_phnum * iehdr->e_phentsize)));
isec = 0;
for (s = ibfd->sections; s != NULL; s = s->next)
if (! phdr_included)
{
boolean matching_lma = false;
boolean lma_conflict = false;
bfd_vma suggested_lma = 0;
asection * os;
phdr_included = m->includes_phdrs =
(p->p_offset <= (bfd_vma) iehdr->e_phoff
&& (p->p_offset + p->p_filesz
>= ((bfd_vma) iehdr->e_phoff
+ iehdr->e_phnum * iehdr->e_phentsize)));
}
if (csecs == 0)
{
/* Special segments, such as the PT_PHDR segment, may contain
no sections, but ordinary, loadable segments should contain
something. */
#define is_contained_by(addr, len, bottom, phdr) \
((addr) >= (bottom) \
&& ( ((addr) + (len)) <= ((bottom) + (phdr)->p_memsz) \
|| ((addr) + (len)) <= ((bottom) + (phdr)->p_filesz)))
if (p->p_type == PT_LOAD)
_bfd_error_handler
(_("%s: warning: Empty loadable segment detected\n"),
bfd_get_filename (ibfd));
m->count = 0;
*pm = m;
pm = &m->next;
continue;
}
/* Now scan the sections in the input BFD again and attempt
to add their corresponding output sections to the segment map.
The problem here is how to handle an output section which has
been moved (ie had its LMA changed). There are four possibilities:
1. None of the sections have been moved.
In this case we can continue to use the segment LMA from the
input BFD.
2. All of the sections have been moved by the same amount.
In this case we can change the segment's LMA to match the LMA
of the first section.
3. Some of the sections have been moved, others have not.
In this case those sections which have not been moved can be
placed in the current segment which will have to have its size,
and possibly its LMA changed, and a new segment or segments will
have to be created to contain the other sections.
4. The sections have been moved, but not be the same amount.
In this case we can change the segment's LMA to match the LMA
of the first section and we will have to create a new segment
or segments to contain the other sections.
In order to save time, we allocate an array to hold the section
pointers that we are interested in. As these sections get assigned
to a segment, they are removed from this array. */
sections = (asection **) bfd_malloc (sizeof (asection *) * csecs);
if (sections == NULL)
return false;
/* Step One: Scan for segment vs section LMA conflicts.
Also add the sections to the section array allocated above.
Also add the sections to the current segment. In the common
case, where the sections have not been moved, this means that
we have completely filled the segment, and there is nothing
more to do. */
isec = 0;
matching_lma = false;
suggested_lma = 0;
for (j = 0, s = ibfd->sections; s != NULL; s = s->next)
{
os = s->output_section;
if ((is_contained_by (s->vma, s->_raw_size, p->p_vaddr, p)
|| (p->p_vaddr == 0
&& p->p_filesz > 0
&& (s->flags & SEC_HAS_CONTENTS) != 0
&& s->_raw_size > 0
&& (bfd_vma) s->filepos >= p->p_offset
&& ((bfd_vma) s->filepos + s->_raw_size
<= p->p_offset + p->p_filesz)))
if ((IS_CONTAINED_BY (s->vma, s->_raw_size, p->p_vaddr, p)
|| IS_SOLARIS_PT_INTERP (p, s))
&& (s->flags & SEC_ALLOC) != 0
&& os != NULL)
{
sections[j++] = s;
/* The Solaris native linker always sets p_paddr to 0.
We try to catch that case here, and set it to the
correct value. */
@ -3371,42 +3470,154 @@ copy_private_bfd_data (ibfd, obfd)
: 0))))
m->p_paddr = p->p_vaddr;
m->sections[isec] = os;
++isec;
/* Match up the physical address of the segment with the
LMA addresses of its sections. */
if (is_contained_by (os->lma, os->_raw_size, m->p_paddr, p))
matching_lma = true;
LMA address of the output section. */
if (IS_CONTAINED_BY (os->lma, os->_raw_size, m->p_paddr, p))
{
if (matching_lma == 0)
matching_lma = os->lma;
/* We assume that if the section fits within the segment
that it does not overlap any other section within that
segment. */
m->sections[isec++] = os;
}
else if (suggested_lma == 0)
suggested_lma = os->lma;
else if (! is_contained_by (os->lma, os->_raw_size,
suggested_lma, p))
lma_conflict = true;
}
if (matching_lma)
{
if (suggested_lma)
(*_bfd_error_handler)
(_("Warning: Some sections' LMAs lie outside their segment's physical address\n"));
}
else if (lma_conflict)
{
(*_bfd_error_handler)
(_("Warning: Cannot change segment's physical address to contain all of its sections' LMAs\n"));
}
else if (suggested_lma)
{
m->p_paddr = suggested_lma;
}
}
BFD_ASSERT (isec == csecs);
m->count = csecs;
*pm = m;
pm = &m->next;
BFD_ASSERT (j == csecs);
/* Step Two: Adjust the physical address of the current segment,
if necessary. */
if (isec == csecs)
{
/* All of the sections fitted within the segment as currently
specified. This is the default case. Add the segment to
the list of built segments and carry on to process the next
program header in the input BFD. */
m->count = csecs;
*pm = m;
pm = &m->next;
free (sections);
continue;
}
else if (matching_lma != 0)
{
/* At least one section fits inside the current segment.
Keep it, but modify its physical address to match the
LMA of the first section that fitted. */
m->p_paddr = matching_lma;
}
else
{
/* None of the sections fitted inside the current segment.
Change the current segment's physical address to match
the LMA of the first section. */
m->p_paddr = suggested_lma;
}
/* Step Three: Loop over the sections again, this time assigning
those that fit to the current segment and remvoing them from the
sections array; but making sure not to leave large gaps. Once all
possible sections have been assigned to the current segment it is
added to the list of built segments and if sections still remain
to be assigned, a new segment is constructed before repeating
the loop. */
isec = 0;
do
{
m->count = 0;
suggested_lma = 0;
/* Fill the current segment with sections that fit. */
for (j = 0; j < csecs; j++)
{
s = sections[j];
if (s == NULL)
continue;
os = s->output_section;
if (IS_CONTAINED_BY (os->lma, os->_raw_size, m->p_paddr, p))
{
if (m->count == 0)
{
/* If the first section in a segment does not start at
the beginning of the segment, then something is wrong. */
if (os->lma != m->p_paddr)
abort ();
}
else
{
asection * prev_sec;
bfd_vma maxpagesize;
prev_sec = m->sections[m->count - 1];
maxpagesize = get_elf_backend_data (obfd)->maxpagesize;
/* If the gap between the end of the previous section
and the start of this section is more than maxpagesize
then we need to start a new segment. */
if (BFD_ALIGN (prev_sec->lma + prev_sec->_raw_size, maxpagesize)
< BFD_ALIGN (os->lma, maxpagesize))
{
if (suggested_lma == 0)
suggested_lma = os->lma;
continue;
}
}
m->sections[m->count++] = os;
++isec;
sections[j] = NULL;
}
else if (suggested_lma == 0)
suggested_lma = os->lma;
}
BFD_ASSERT (m->count > 0);
/* Add the current segment to the list of built segments. */
*pm = m;
pm = &m->next;
if (isec < csecs)
{
/* We still have not allocated all of the sections to
segments. Create a new segment here, initialise it
and carry on looping. */
m = ((struct elf_segment_map *)
bfd_alloc (obfd,
(sizeof (struct elf_segment_map)
+ ((size_t) csecs - 1) * sizeof (asection *))));
if (m == NULL)
return false;
/* Initialise the fields of the segment map. Set the physical
physical address to the LMA of the first section that has
not yet been assigned. */
m->next = NULL;
m->p_type = p->p_type;
m->p_flags = p->p_flags;
m->p_flags_valid = 1;
m->p_paddr = suggested_lma;
m->p_paddr_valid = 1;
m->includes_filehdr = 0;
m->includes_phdrs = 0;
}
}
while (isec < csecs);
free (sections);
}
/* The Solaris linker creates program headers in which all the
@ -3424,6 +3635,33 @@ copy_private_bfd_data (ibfd, obfd)
elf_tdata (obfd)->segment_map = mfirst;
#if 0
/* Final Step: Sort the segments into ascending order of physical address. */
if (mfirst != NULL)
{
struct elf_segment_map* prev;
prev = mfirst;
for (m = mfirst->next; m != NULL; prev = m, m = m->next)
{
/* Yes I know - its a bubble sort....*/
if (m->next != NULL && (m->next->p_paddr < m->p_paddr))
{
/* swap m and m->next */
prev->next = m->next;
m->next = m->next->next;
prev->next->next = m;
/* restart loop. */
m = mfirst;
}
}
}
#endif
#undef IS_CONTAINED_BY
#undef IS_SOLARIS_PT_INTERP
return true;
}
@ -3618,8 +3856,8 @@ swap_out_syms (abfd, sttp, relocatable_p)
sym.st_value = value >= 16 ? 16 : (1 << bfd_log2 (value));
else
sym.st_value = type_ptr->internal_elf_sym.st_value;
sym.st_shndx = _bfd_elf_section_from_bfd_section (abfd,
syms[idx]->section);
sym.st_shndx = _bfd_elf_section_from_bfd_section
(abfd, syms[idx]->section);
}
else
{
@ -3824,7 +4062,8 @@ _bfd_elf_get_symtab (abfd, alocation)
bfd *abfd;
asymbol **alocation;
{
long symcount = get_elf_backend_data (abfd)->s->slurp_symbol_table (abfd, alocation, false);
long symcount = get_elf_backend_data (abfd)->s->slurp_symbol_table
(abfd, alocation, false);
if (symcount >= 0)
bfd_get_symcount (abfd) = symcount;
@ -3836,7 +4075,8 @@ _bfd_elf_canonicalize_dynamic_symtab (abfd, alocation)
bfd *abfd;
asymbol **alocation;
{
return get_elf_backend_data (abfd)->s->slurp_symbol_table (abfd, alocation, true);
return get_elf_backend_data (abfd)->s->slurp_symbol_table
(abfd, alocation, true);
}
/* Return the size required for the dynamic reloc entries. Any
@ -4283,8 +4523,8 @@ _bfd_elf_set_section_contents (abfd, section, location, offset, count)
Elf_Internal_Shdr *hdr;
if (! abfd->output_has_begun
&& ! _bfd_elf_compute_section_file_positions (abfd,
(struct bfd_link_info *) NULL))
&& ! _bfd_elf_compute_section_file_positions
(abfd, (struct bfd_link_info *) NULL))
return false;
hdr = &elf_section_data (section)->this_hdr;