Add LMA memory region functionality.
This commit is contained in:
parent
a4f419971f
commit
562d3460fb
9 changed files with 138 additions and 46 deletions
21
ld/ChangeLog
21
ld/ChangeLog
|
@ -1,3 +1,24 @@
|
||||||
|
2000-02-16 Timothy Wall <twall@cygnus.com>
|
||||||
|
|
||||||
|
* mri.c (mri_draw_tree): Add default LMA region argument to call
|
||||||
|
to lang_leave_output_section_statement.
|
||||||
|
* ldlang.h: Update prototypes with LMA region arguments.
|
||||||
|
* ldlang.c (lang_size_sections): Encapsulate region bounds
|
||||||
|
checking in os_check_region call.
|
||||||
|
(os_check_region): New function.
|
||||||
|
(lang_output_section_statement_lookup): Initialize lma_region.
|
||||||
|
(lang_leave_output_section_statement): Add LMA region argument.
|
||||||
|
(lang_leave_overlay): Ditto.
|
||||||
|
* ldgram.y: Handle LMA region syntax.
|
||||||
|
* ld.texinfo (Output Section Description): Describe LMA region usage.
|
||||||
|
* emultempl/armelf.em (gld$place_orphan): Add default value for
|
||||||
|
lma region in call to lang_leave_output_statement.
|
||||||
|
* emultempl/elf32.em (gld$place_orphan): Add default value for
|
||||||
|
lma region in call to lang_leave_output_statement.
|
||||||
|
* emultempl/pe.em (gld$place_orphan): Add default value for
|
||||||
|
lma region in call to lang_leave_output_statement.
|
||||||
|
|
||||||
|
|
||||||
2000-02-04 Timothy Wall <twall@redhat.com>
|
2000-02-04 Timothy Wall <twall@redhat.com>
|
||||||
|
|
||||||
* ldlang.c (lang_check_section_addresses): Use bytes instead of
|
* ldlang.c (lang_check_section_addresses): Use bytes instead of
|
||||||
|
|
|
@ -942,7 +942,8 @@ gld${EMULATION_NAME}_place_orphan (file, s)
|
||||||
wild_doit (&os->children, s, os, file);
|
wild_doit (&os->children, s, os, file);
|
||||||
|
|
||||||
lang_leave_output_section_statement
|
lang_leave_output_section_statement
|
||||||
((bfd_vma) 0, "*default*", (struct lang_output_section_phdr_list *) NULL);
|
((bfd_vma) 0, "*default*", (struct lang_output_section_phdr_list *) NULL,
|
||||||
|
"*default*");
|
||||||
stat_ptr = &add;
|
stat_ptr = &add;
|
||||||
|
|
||||||
if (*ps == '\0' && config.build_constructors)
|
if (*ps == '\0' && config.build_constructors)
|
||||||
|
|
|
@ -1024,7 +1024,8 @@ gld${EMULATION_NAME}_place_orphan (file, s)
|
||||||
wild_doit (&os->children, s, os, file);
|
wild_doit (&os->children, s, os, file);
|
||||||
|
|
||||||
lang_leave_output_section_statement
|
lang_leave_output_section_statement
|
||||||
((bfd_vma) 0, "*default*", (struct lang_output_section_phdr_list *) NULL);
|
((bfd_vma) 0, "*default*", (struct lang_output_section_phdr_list *) NULL,
|
||||||
|
"*default*");
|
||||||
stat_ptr = &add;
|
stat_ptr = &add;
|
||||||
|
|
||||||
if (*ps == '\0' && config.build_constructors)
|
if (*ps == '\0' && config.build_constructors)
|
||||||
|
|
|
@ -1146,7 +1146,8 @@ gld_${EMULATION_NAME}_place_orphan (file, s)
|
||||||
|
|
||||||
lang_leave_output_section_statement
|
lang_leave_output_section_statement
|
||||||
((bfd_vma) 0, "*default*",
|
((bfd_vma) 0, "*default*",
|
||||||
(struct lang_output_section_phdr_list *) NULL);
|
(struct lang_output_section_phdr_list *) NULL,
|
||||||
|
"*default*");
|
||||||
|
|
||||||
/* Now stick the new statement list right after PLACE. */
|
/* Now stick the new statement list right after PLACE. */
|
||||||
if (place != NULL)
|
if (place != NULL)
|
||||||
|
|
|
@ -2127,7 +2127,7 @@ The full description of an output section looks like this:
|
||||||
@var{output-section-command}
|
@var{output-section-command}
|
||||||
@var{output-section-command}
|
@var{output-section-command}
|
||||||
@dots{}
|
@dots{}
|
||||||
@} [>@var{region}] [:@var{phdr} :@var{phdr} @dots{}] [=@var{fillexp}]
|
@} [>@var{region}] [AT>@var{lma_region}] [:@var{phdr} :@var{phdr} @dots{}] [=@var{fillexp}]
|
||||||
@end group
|
@end group
|
||||||
@end smallexample
|
@end smallexample
|
||||||
|
|
||||||
|
@ -2632,7 +2632,7 @@ like this:
|
||||||
@var{output-section-command}
|
@var{output-section-command}
|
||||||
@var{output-section-command}
|
@var{output-section-command}
|
||||||
@dots{}
|
@dots{}
|
||||||
@} [>@var{region}] [:@var{phdr} :@var{phdr} @dots{}] [=@var{fillexp}]
|
@} [>@var{region}] [AT>@var{lma_region}] [:@var{phdr} :@var{phdr} @dots{}] [=@var{fillexp}]
|
||||||
@end group
|
@end group
|
||||||
@end smallexample
|
@end smallexample
|
||||||
We've already described @var{section}, @var{address}, and
|
We've already described @var{section}, @var{address}, and
|
||||||
|
@ -2686,6 +2686,7 @@ SECTIONS @{
|
||||||
|
|
||||||
@node Output Section LMA
|
@node Output Section LMA
|
||||||
@subsubsection Output section LMA
|
@subsubsection Output section LMA
|
||||||
|
@kindex AT>@var{lma_region}
|
||||||
@kindex AT(@var{lma})
|
@kindex AT(@var{lma})
|
||||||
@cindex load address
|
@cindex load address
|
||||||
@cindex section load address
|
@cindex section load address
|
||||||
|
@ -2696,7 +2697,9 @@ Address}).
|
||||||
|
|
||||||
The linker will normally set the LMA equal to the VMA. You can change
|
The linker will normally set the LMA equal to the VMA. You can change
|
||||||
that by using the @code{AT} keyword. The expression @var{lma} that
|
that by using the @code{AT} keyword. The expression @var{lma} that
|
||||||
follows the @code{AT} keyword specifies the load address of the section.
|
follows the @code{AT} keyword specifies the load address of the
|
||||||
|
section. Alternatively, with @samp{AT>@var{lma_region}} expression,
|
||||||
|
you may specify a memory region for the section's load address. @xref{MEMORY}.
|
||||||
|
|
||||||
@cindex ROM initialized data
|
@cindex ROM initialized data
|
||||||
@cindex initialized data in ROM
|
@cindex initialized data in ROM
|
||||||
|
|
14
ld/ldgram.y
14
ld/ldgram.y
|
@ -92,6 +92,7 @@ static int error_index;
|
||||||
%type <integer> fill_opt
|
%type <integer> fill_opt
|
||||||
%type <name_list> exclude_name_list
|
%type <name_list> exclude_name_list
|
||||||
%type <name> memspec_opt casesymlist
|
%type <name> memspec_opt casesymlist
|
||||||
|
%type <name> memspec_at_opt
|
||||||
%type <cname> wildcard_name
|
%type <cname> wildcard_name
|
||||||
%type <wildcard> wildcard_spec
|
%type <wildcard> wildcard_spec
|
||||||
%token <integer> INT
|
%token <integer> INT
|
||||||
|
@ -799,6 +800,11 @@ exp :
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
memspec_at_opt:
|
||||||
|
AT '>' NAME { $$ = $3; }
|
||||||
|
| { $$ = "*default*"; }
|
||||||
|
;
|
||||||
|
|
||||||
opt_at:
|
opt_at:
|
||||||
AT '(' exp ')' { $$ = $3; }
|
AT '(' exp ')' { $$ = $3; }
|
||||||
| { $$ = 0; }
|
| { $$ = 0; }
|
||||||
|
@ -815,10 +821,10 @@ section: NAME { ldlex_expression(); }
|
||||||
}
|
}
|
||||||
statement_list_opt
|
statement_list_opt
|
||||||
'}' { ldlex_popstate (); ldlex_expression (); }
|
'}' { ldlex_popstate (); ldlex_expression (); }
|
||||||
memspec_opt phdr_opt fill_opt
|
memspec_opt memspec_at_opt phdr_opt fill_opt
|
||||||
{
|
{
|
||||||
ldlex_popstate ();
|
ldlex_popstate ();
|
||||||
lang_leave_output_section_statement ($13, $11, $12);
|
lang_leave_output_section_statement ($14, $11, $13, $12);
|
||||||
}
|
}
|
||||||
opt_comma
|
opt_comma
|
||||||
| OVERLAY
|
| OVERLAY
|
||||||
|
@ -832,10 +838,10 @@ section: NAME { ldlex_expression(); }
|
||||||
overlay_section
|
overlay_section
|
||||||
'}'
|
'}'
|
||||||
{ ldlex_popstate (); ldlex_expression (); }
|
{ ldlex_popstate (); ldlex_expression (); }
|
||||||
memspec_opt phdr_opt fill_opt
|
memspec_opt memspec_at_opt phdr_opt fill_opt
|
||||||
{
|
{
|
||||||
ldlex_popstate ();
|
ldlex_popstate ();
|
||||||
lang_leave_overlay ($14, $12, $13);
|
lang_leave_overlay ($15, $12, $14, $13);
|
||||||
}
|
}
|
||||||
opt_comma
|
opt_comma
|
||||||
| /* The GROUP case is just enough to support the gcc
|
| /* The GROUP case is just enough to support the gcc
|
||||||
|
|
121
ld/ldlang.c
121
ld/ldlang.c
|
@ -682,6 +682,7 @@ lang_output_section_statement_lookup (name)
|
||||||
lookup = (lang_output_section_statement_type *)
|
lookup = (lang_output_section_statement_type *)
|
||||||
new_stat (lang_output_section_statement, stat_ptr);
|
new_stat (lang_output_section_statement, stat_ptr);
|
||||||
lookup->region = (lang_memory_region_type *) NULL;
|
lookup->region = (lang_memory_region_type *) NULL;
|
||||||
|
lookup->lma_region = (lang_memory_region_type *) NULL;
|
||||||
lookup->fill = 0;
|
lookup->fill = 0;
|
||||||
lookup->block_value = 1;
|
lookup->block_value = 1;
|
||||||
lookup->name = name;
|
lookup->name = name;
|
||||||
|
@ -2695,6 +2696,43 @@ _("%X%P: section %s [%V -> %V] overlaps section %s [%V -> %V]\n"),
|
||||||
|
|
||||||
static boolean relax_again;
|
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. */
|
/* Set the sizes for all the output sections. */
|
||||||
|
|
||||||
bfd_vma
|
bfd_vma
|
||||||
|
@ -2853,37 +2891,35 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
|
||||||
{
|
{
|
||||||
os->region->current = dot;
|
os->region->current = dot;
|
||||||
|
|
||||||
/* Make sure the new address is within the region. We
|
/* Make sure the new address is within the region. */
|
||||||
explicitly permit the current address to be at the
|
os_region_check (os, os->region, os->addr_tree,
|
||||||
exact end of the region when the VMA is non-zero,
|
os->bfd_section->vma);
|
||||||
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 there's no load address specified, use the run region as
|
||||||
if (os->addr_tree != (etree_type *) NULL)
|
the load region */
|
||||||
{
|
if (os->lma_region == NULL && os->load_base == NULL)
|
||||||
einfo (_("%X%P: address 0x%v of %B section %s is not within region %s\n"),
|
os->lma_region = os->region;
|
||||||
os->region->current,
|
|
||||||
os->bfd_section->owner,
|
if (os->lma_region != NULL)
|
||||||
os->bfd_section->name,
|
{
|
||||||
os->region->name);
|
if (os->load_base != NULL)
|
||||||
}
|
{
|
||||||
else
|
einfo (_("%X%P: use an absolute load address or a load memory region, not both\n"));
|
||||||
{
|
}
|
||||||
einfo (_("%X%P: region %s is full (%B section %s)\n"),
|
else
|
||||||
os->region->name,
|
{
|
||||||
os->bfd_section->owner,
|
/* don't allocate twice */
|
||||||
os->bfd_section->name);
|
if (os->lma_region != os->region)
|
||||||
}
|
{
|
||||||
/* Reset the region pointer. */
|
/* set load_base, which will be handled later */
|
||||||
os->region->current = os->region->origin;
|
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;
|
break;
|
||||||
|
@ -4259,13 +4295,22 @@ lang_float (maybe)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lang_leave_output_section_statement (fill, memspec, phdrs)
|
lang_leave_output_section_statement (fill, memspec, phdrs, lma_memspec)
|
||||||
bfd_vma fill;
|
bfd_vma fill;
|
||||||
const char *memspec;
|
const char *memspec;
|
||||||
struct lang_output_section_phdr_list *phdrs;
|
struct lang_output_section_phdr_list *phdrs;
|
||||||
|
const char *lma_memspec;
|
||||||
{
|
{
|
||||||
current_section->fill = fill;
|
current_section->fill = fill;
|
||||||
current_section->region = lang_memory_region_lookup (memspec);
|
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;
|
current_section->phdrs = phdrs;
|
||||||
stat_ptr = &statement_list;
|
stat_ptr = &statement_list;
|
||||||
}
|
}
|
||||||
|
@ -4644,7 +4689,8 @@ lang_leave_overlay_section (fill, phdrs)
|
||||||
|
|
||||||
name = current_section->name;
|
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. */
|
/* Define the magic symbols. */
|
||||||
|
|
||||||
|
@ -4674,12 +4720,14 @@ lang_leave_overlay_section (fill, phdrs)
|
||||||
looks through all the sections in the overlay and sets them. */
|
looks through all the sections in the overlay and sets them. */
|
||||||
|
|
||||||
void
|
void
|
||||||
lang_leave_overlay (fill, memspec, phdrs)
|
lang_leave_overlay (fill, memspec, phdrs, lma_memspec)
|
||||||
bfd_vma fill;
|
bfd_vma fill;
|
||||||
const char *memspec;
|
const char *memspec;
|
||||||
struct lang_output_section_phdr_list *phdrs;
|
struct lang_output_section_phdr_list *phdrs;
|
||||||
|
const char *lma_memspec;
|
||||||
{
|
{
|
||||||
lang_memory_region_type *region;
|
lang_memory_region_type *region;
|
||||||
|
lang_memory_region_type *lma_region;
|
||||||
struct overlay_list *l;
|
struct overlay_list *l;
|
||||||
struct lang_nocrossref *nocrossref;
|
struct lang_nocrossref *nocrossref;
|
||||||
|
|
||||||
|
@ -4688,6 +4736,11 @@ lang_leave_overlay (fill, memspec, phdrs)
|
||||||
else
|
else
|
||||||
region = lang_memory_region_lookup (memspec);
|
region = lang_memory_region_lookup (memspec);
|
||||||
|
|
||||||
|
if (lma_memspec == NULL)
|
||||||
|
lma_region = NULL;
|
||||||
|
else
|
||||||
|
lma_region = lang_memory_region_lookup (lma_memspec);
|
||||||
|
|
||||||
nocrossref = NULL;
|
nocrossref = NULL;
|
||||||
|
|
||||||
l = overlay_list;
|
l = overlay_list;
|
||||||
|
@ -4699,6 +4752,8 @@ lang_leave_overlay (fill, memspec, phdrs)
|
||||||
l->os->fill = fill;
|
l->os->fill = fill;
|
||||||
if (region != NULL && l->os->region == NULL)
|
if (region != NULL && l->os->region == NULL)
|
||||||
l->os->region = region;
|
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)
|
if (phdrs != NULL && l->os->phdrs == NULL)
|
||||||
l->os->phdrs = phdrs;
|
l->os->phdrs = phdrs;
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,7 @@ typedef struct lang_output_section_statement_struct
|
||||||
flagword flags; /* Or together of all input sections */
|
flagword flags; /* Or together of all input sections */
|
||||||
enum section_type sectype;
|
enum section_type sectype;
|
||||||
struct memory_region_struct *region;
|
struct memory_region_struct *region;
|
||||||
|
struct memory_region_struct *lma_region;
|
||||||
size_t block_value;
|
size_t block_value;
|
||||||
fill_type fill;
|
fill_type fill;
|
||||||
|
|
||||||
|
@ -409,7 +410,8 @@ extern void lang_add_attribute PARAMS ((enum statement_enum));
|
||||||
extern void lang_startup PARAMS ((const char *));
|
extern void lang_startup PARAMS ((const char *));
|
||||||
extern void lang_float PARAMS ((enum bfd_boolean));
|
extern void lang_float PARAMS ((enum bfd_boolean));
|
||||||
extern void lang_leave_output_section_statement
|
extern void lang_leave_output_section_statement
|
||||||
PARAMS ((bfd_vma, const char *, struct lang_output_section_phdr_list *));
|
PARAMS ((bfd_vma, const char *, struct lang_output_section_phdr_list *,
|
||||||
|
const char *));
|
||||||
extern void lang_abs_symbol_at_end_of PARAMS ((const char *, const char *));
|
extern void lang_abs_symbol_at_end_of PARAMS ((const char *, const char *));
|
||||||
extern void lang_abs_symbol_at_beginning_of PARAMS ((const char *,
|
extern void lang_abs_symbol_at_beginning_of PARAMS ((const char *,
|
||||||
const char *));
|
const char *));
|
||||||
|
@ -475,7 +477,8 @@ extern void lang_enter_overlay_section PARAMS ((const char *));
|
||||||
extern void lang_leave_overlay_section
|
extern void lang_leave_overlay_section
|
||||||
PARAMS ((bfd_vma, struct lang_output_section_phdr_list *));
|
PARAMS ((bfd_vma, struct lang_output_section_phdr_list *));
|
||||||
extern void lang_leave_overlay
|
extern void lang_leave_overlay
|
||||||
PARAMS ((bfd_vma, const char *, struct lang_output_section_phdr_list *));
|
PARAMS ((bfd_vma, const char *, struct lang_output_section_phdr_list *,
|
||||||
|
const char *));
|
||||||
|
|
||||||
extern struct bfd_elf_version_tree *lang_elf_version_info;
|
extern struct bfd_elf_version_tree *lang_elf_version_info;
|
||||||
|
|
||||||
|
|
3
ld/mri.c
3
ld/mri.c
|
@ -266,7 +266,8 @@ mri_draw_tree ()
|
||||||
}
|
}
|
||||||
|
|
||||||
lang_leave_output_section_statement
|
lang_leave_output_section_statement
|
||||||
(0, "*default*", (struct lang_output_section_phdr_list *) NULL);
|
(0, "*default*", (struct lang_output_section_phdr_list *) NULL,
|
||||||
|
"*default*");
|
||||||
|
|
||||||
p = p->next;
|
p = p->next;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue