#include "ldgram.h"
#include "ldexp.h"
#include "ldlang.h"
-#include "ldemul.h"
#include "ldlex.h"
#include "ldmisc.h"
#include "ldctor.h"
#include "ldfile.h"
+#include "ldemul.h"
#include "fnmatch.h"
#include "demangle.h"
static boolean map_option_f;
static bfd_vma print_dot;
static lang_input_statement_type *first_file;
-static lang_statement_list_type lang_output_section_statement;
static CONST char *current_target;
static CONST char *output_target;
static lang_statement_list_type statement_list;
/* EXPORTS */
lang_output_section_statement_type *abs_output_section;
+lang_statement_list_type lang_output_section_statement;
lang_statement_list_type *stat_ptr = &statement_list;
lang_statement_list_type file_chain = { NULL, NULL };
const char *entry_symbol = NULL;
lookup = (lang_output_section_statement_type *)
new_stat (lang_output_section_statement, stat_ptr);
lookup->region = (lang_memory_region_type *) NULL;
+ lookup->lma_region = (lang_memory_region_type *) NULL;
lookup->fill = 0;
lookup->block_value = 1;
lookup->name = name;
/* If supplied an aligment, then force it. */
if (output->section_alignment != -1)
output->bfd_section->alignment_power = output->section_alignment;
+
+ if (section->flags & SEC_BLOCK)
+ {
+ section->output_section->flags |= SEC_BLOCK;
+ /* FIXME: This value should really be obtained from the bfd... */
+ output->block_value = 128;
+ }
}
}
/* Get the chosen target. */
target = bfd_search_for_target (get_target, (void *) output_target);
- if (command_line.endian == ENDIAN_BIG)
- desired_endian = BFD_ENDIAN_BIG;
- else
- desired_endian = BFD_ENDIAN_LITTLE;
-
- /* See if the target has the wrong endianness. This should not happen
- if the linker script has provided big and little endian alternatives,
- but some scrips don't do this. */
- if (target->byteorder != desired_endian)
+ /* If the target is not supported, we cannot do anything. */
+ if (target != NULL)
{
- /* If it does, then see if the target provides
- an alternative with the correct endianness. */
- if (target->alternative_target != NULL
- && (target->alternative_target->byteorder == desired_endian))
- output_target = target->alternative_target->name;
+ if (command_line.endian == ENDIAN_BIG)
+ desired_endian = BFD_ENDIAN_BIG;
else
+ desired_endian = BFD_ENDIAN_LITTLE;
+
+ /* See if the target has the wrong endianness. This should not happen
+ if the linker script has provided big and little endian alternatives,
+ but some scrips don't do this. */
+ if (target->byteorder != desired_endian)
{
- /* Try to find a target as similar as possible to the default
- target, but which has the desired endian characteristic. */
- (void) bfd_search_for_target (closest_target_match, (void *) target);
-
- /* Oh dear - we could not find any targets that satisfy our requirements. */
- if (winner == NULL)
- einfo (_("%P: warning: could not find any targets that match endianness requirement\n"));
+ /* If it does, then see if the target provides
+ an alternative with the correct endianness. */
+ if (target->alternative_target != NULL
+ && (target->alternative_target->byteorder == desired_endian))
+ output_target = target->alternative_target->name;
else
- output_target = winner->name;
+ {
+ /* Try to find a target as similar as possible to the default
+ target, but which has the desired endian characteristic. */
+ (void) bfd_search_for_target (closest_target_match, (void *) target);
+
+ /* Oh dear - we could not find any targets that satisfy our
+ requirements. */
+ if (winner == NULL)
+ einfo (_("%P: warning: could not find any targets that match endianness requirement\n"));
+ else
+ output_target = winner->name;
+ }
}
}
}
/* If we are being called from within a group, and this
is an archive which has already been searched, then
- force it to be researched. */
+ force it to be researched unless the whole archive
+ has been loaded already. */
if (force
+ && !s->input_statement.whole_archive
&& s->input_statement.loaded
&& bfd_check_format (s->input_statement.the_bfd,
bfd_archive))
{
asection *i = in->section;
bfd_size_type size = i->_cooked_size != 0 ? i->_cooked_size : i->_raw_size;
- int opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
+ unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+ ldfile_output_machine);
if (size != 0)
{
print_space ();
bfd_vma addr;
bfd_size_type size;
const char *name;
- int opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
+ unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+ ldfile_output_machine);
for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
print_space ();
int i;
bfd_vma addr;
bfd_size_type size;
- int opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
+ unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+ ldfile_output_machine);
for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
print_space ();
{
int len;
bfd_vma addr;
- int opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
+ unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+ ldfile_output_machine);
minfo (" *fill*");
inserting a magic 'padding' statement.
*/
- int opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
+ unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+ ldfile_output_machine);
unsigned int alignment_needed = align_power (dot, power) - dot;
if (alignment_needed != 0)
{
lang_input_section_type *is = &((*this_ptr)->input_section);
asection *i = is->section;
- int opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
+ unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+ ldfile_output_machine);
if (is->ifile->just_syms_flag == false)
{
lang_check_section_addresses ()
{
asection * s;
- int opb = bfd_octets_per_byte (output_bfd);
+ unsigned opb = bfd_octets_per_byte (output_bfd);
/* Scan all sections in the output list. */
for (s = output_bfd->sections; s != NULL; s = s->next)
overlapping VMAs but they must have distinct LMAs. */
s_start = bfd_section_lma (output_bfd, s);
os_start = bfd_section_lma (output_bfd, os);
- s_end = s_start + bfd_section_size (output_bfd, s) - 1;
- os_end = os_start + bfd_section_size (output_bfd, os) - 1;
+ s_end = s_start + bfd_section_size (output_bfd, s) / opb - 1;
+ os_end = os_start + bfd_section_size (output_bfd, os) / opb - 1;
/* Look for an overlap. */
if ((s_end < os_start) || (s_start > os_end))
static boolean relax_again;
+/* Make sure the new address is within the region. We explicitly permit the
+ current address to be at the exact end of the region when the address is
+ non-zero, in case the region is at the end of addressable memory and the
+ calculation wraps around. */
+
+static void
+os_region_check (os, region, tree, base)
+ lang_output_section_statement_type *os;
+ struct memory_region_struct *region;
+ etree_type *tree;
+ bfd_vma base;
+{
+ if ((region->current < region->origin
+ || (region->current - region->origin > region->length))
+ && ((region->current != region->origin + region->length)
+ || base == 0))
+ {
+ if (tree != (etree_type *) NULL)
+ {
+ einfo (_("%X%P: address 0x%v of %B section %s is not within region %s\n"),
+ region->current,
+ os->bfd_section->owner,
+ os->bfd_section->name,
+ region->name);
+ }
+ else
+ {
+ einfo (_("%X%P: region %s is full (%B section %s)\n"),
+ region->name,
+ os->bfd_section->owner,
+ os->bfd_section->name);
+ }
+ /* Reset the region pointer. */
+ region->current = region->origin;
+ }
+}
+
/* Set the sizes for all the output sections. */
bfd_vma
bfd_vma dot;
boolean relax;
{
- int opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
+ unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+ ldfile_output_machine);
/* Size up the sections from their constituent parts. */
for (; s != (lang_statement_union_type *) NULL; s = s->next)
/* put the section within the requested block size, or align at
the block boundary */
- after = ALIGN_N (os->bfd_section->vma,
- os->bfd_section->_raw_size / opb,
+ after = ALIGN_N (os->bfd_section->vma
+ + os->bfd_section->_raw_size / opb,
/* The coercion here is important, see ld.h. */
(bfd_vma) os->block_value);
{
os->region->current = dot;
- /* Make sure the new address is within the region. We
- explicitly permit the current address to be at the
- exact end of the region when the VMA is non-zero,
- in case the region is at the end of addressable
- memory and the calculation wraps around. */
- if ((os->region->current < os->region->origin
- || (os->region->current - os->region->origin
- > os->region->length))
- && ((os->region->current
- != os->region->origin + os->region->length)
- || os->bfd_section->vma == 0))
-
- {
- if (os->addr_tree != (etree_type *) NULL)
- {
- einfo (_("%X%P: address 0x%v of %B section %s is not within region %s\n"),
- os->region->current,
- os->bfd_section->owner,
- os->bfd_section->name,
- os->region->name);
- }
- else
- {
- einfo (_("%X%P: region %s is full (%B section %s)\n"),
- os->region->name,
- os->bfd_section->owner,
- os->bfd_section->name);
- }
- /* Reset the region pointer. */
- os->region->current = os->region->origin;
- }
+ /* Make sure the new address is within the region. */
+ os_region_check (os, os->region, os->addr_tree,
+ os->bfd_section->vma);
+
+ /* if there's no load address specified, use the run region as
+ the load region */
+ if (os->lma_region == NULL && os->load_base == NULL)
+ os->lma_region = os->region;
+
+ if (os->lma_region != NULL)
+ {
+ if (os->load_base != NULL)
+ {
+ einfo (_("%X%P: use an absolute load address or a load memory region, not both\n"));
+ }
+ else
+ {
+ /* don't allocate twice */
+ if (os->lma_region != os->region)
+ {
+ /* set load_base, which will be handled later */
+ os->load_base = exp_intop (os->lma_region->current);
+ os->lma_region->current +=
+ os->bfd_section->_raw_size / opb;
+ os_region_check (os, os->lma_region, NULL,
+ os->bfd_section->lma);
+ }
+ }
+ }
}
}
break;
switch (s->data_statement.type)
{
+ default:
+ abort();
case QUAD:
case SQUAD:
size = QUAD_SIZE;
fill_type fill;
bfd_vma dot;
{
- int opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
+ unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+ ldfile_output_machine);
for (; s != (lang_statement_union_type *) NULL; s = s->next)
{
dot = os->bfd_section->vma + os->bfd_section->_raw_size / opb;
}
- if (os->load_base)
+ if (os->load_base)
{
/* If nothing has been placed into the output section then
it won't have a bfd_section. */
if (os->bfd_section)
{
os->bfd_section->lma
- = exp_get_abs_int(os->load_base, 0,"load base", lang_final_phase_enum);
+ = exp_get_abs_int(os->load_base, 0,"load base",
+ lang_final_phase_enum);
}
}
}
einfo (_("%F%P: invalid data statement\n"));
}
{
- int size;
+ unsigned int size;
switch (s->data_statement.type)
{
+ default:
+ abort();
case QUAD:
case SQUAD:
size = QUAD_SIZE;
h = bfd_link_hash_lookup (link_info.hash, buf, false, false, true);
if (h != NULL && h->type == bfd_link_hash_undefined)
{
- int opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
+ unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+ ldfile_output_machine);
h->type = bfd_link_hash_defined;
if (s->_cooked_size != 0)
h->u.def.value = s->_cooked_size / opb;
unsigned int power_of_two;
bfd_vma size;
asection *section;
- int opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
+ unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+ ldfile_output_machine);
if (h->type != bfd_link_hash_common)
return true;
return 0;
}
-void
+lang_output_section_statement_type *
lang_enter_output_section_statement (output_section_statement_name,
address_exp, sectype, block_value,
align, subalign, ebase)
"section alignment", 0));
os->load_base = ebase;
+ return os;
}
-
void
lang_final ()
{
}
void
-lang_leave_output_section_statement (fill, memspec, phdrs)
+lang_leave_output_section_statement (fill, memspec, phdrs, lma_memspec)
bfd_vma fill;
const char *memspec;
struct lang_output_section_phdr_list *phdrs;
+ const char *lma_memspec;
{
current_section->fill = fill;
current_section->region = lang_memory_region_lookup (memspec);
+ if (strcmp (lma_memspec, "*default*") != 0)
+ {
+ current_section->lma_region = lang_memory_region_lookup (lma_memspec);
+ /* if no runtime region has been given, but the load region has been,
+ use the load region */
+ if (strcmp (memspec, "*default*") == 0)
+ current_section->region = lang_memory_region_lookup (lma_memspec);
+ }
current_section->phdrs = phdrs;
stat_ptr = &statement_list;
}
name = current_section->name;
- lang_leave_output_section_statement (fill, "*default*", phdrs);
+ lang_leave_output_section_statement (fill, "*default*",
+ phdrs, "*default*");
/* Define the magic symbols. */
looks through all the sections in the overlay and sets them. */
void
-lang_leave_overlay (fill, memspec, phdrs)
+lang_leave_overlay (fill, memspec, phdrs, lma_memspec)
bfd_vma fill;
const char *memspec;
struct lang_output_section_phdr_list *phdrs;
+ const char *lma_memspec;
{
lang_memory_region_type *region;
+ lang_memory_region_type *lma_region;
struct overlay_list *l;
struct lang_nocrossref *nocrossref;
else
region = lang_memory_region_lookup (memspec);
+ if (lma_memspec == NULL)
+ lma_region = NULL;
+ else
+ lma_region = lang_memory_region_lookup (lma_memspec);
+
nocrossref = NULL;
l = overlay_list;
l->os->fill = fill;
if (region != NULL && l->os->region == NULL)
l->os->region = region;
+ if (lma_region != NULL && l->os->lma_region == NULL)
+ l->os->lma_region = lma_region;
if (phdrs != NULL && l->os->phdrs == NULL)
l->os->phdrs = phdrs;