From 562d3460fb28a90014290ac99c543f1085676a26 Mon Sep 17 00:00:00 2001 From: Timothy Wall Date: Wed, 16 Feb 2000 18:53:32 +0000 Subject: [PATCH] Add LMA memory region functionality. --- ld/ChangeLog | 21 +++++++++ ld/emultempl/armelf.em | 3 +- ld/emultempl/elf32.em | 3 +- ld/emultempl/pe.em | 3 +- ld/ld.texinfo | 9 ++-- ld/ldgram.y | 14 ++++-- ld/ldlang.c | 123 +++++++++++++++++++++++++++++++++++-------------- ld/ldlang.h | 7 ++- ld/mri.c | 3 +- 9 files changed, 139 insertions(+), 47 deletions(-) diff --git a/ld/ChangeLog b/ld/ChangeLog index 1ceee7a..da28575 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,24 @@ +2000-02-16 Timothy Wall + + * 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 * ldlang.c (lang_check_section_addresses): Use bytes instead of diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em index 345b12c..f6d5ef4 100644 --- a/ld/emultempl/armelf.em +++ b/ld/emultempl/armelf.em @@ -942,7 +942,8 @@ gld${EMULATION_NAME}_place_orphan (file, s) wild_doit (&os->children, s, os, file); 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; if (*ps == '\0' && config.build_constructors) diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em index f2ff4d8..78676e1 100644 --- a/ld/emultempl/elf32.em +++ b/ld/emultempl/elf32.em @@ -1024,7 +1024,8 @@ gld${EMULATION_NAME}_place_orphan (file, s) wild_doit (&os->children, s, os, file); 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; if (*ps == '\0' && config.build_constructors) diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em index 1ebc091..0112c46 100644 --- a/ld/emultempl/pe.em +++ b/ld/emultempl/pe.em @@ -1146,7 +1146,8 @@ gld_${EMULATION_NAME}_place_orphan (file, s) lang_leave_output_section_statement ((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. */ if (place != NULL) diff --git a/ld/ld.texinfo b/ld/ld.texinfo index a786dd2..8ecdef2 100644 --- a/ld/ld.texinfo +++ b/ld/ld.texinfo @@ -2127,7 +2127,7 @@ The full description of an output section looks like this: @var{output-section-command} @var{output-section-command} @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 smallexample @@ -2632,7 +2632,7 @@ like this: @var{output-section-command} @var{output-section-command} @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 smallexample We've already described @var{section}, @var{address}, and @@ -2686,6 +2686,7 @@ SECTIONS @{ @node Output Section LMA @subsubsection Output section LMA +@kindex AT>@var{lma_region} @kindex AT(@var{lma}) @cindex 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 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 initialized data in ROM diff --git a/ld/ldgram.y b/ld/ldgram.y index 73ee4952..7189812 100644 --- a/ld/ldgram.y +++ b/ld/ldgram.y @@ -92,6 +92,7 @@ static int error_index; %type fill_opt %type exclude_name_list %type memspec_opt casesymlist +%type memspec_at_opt %type wildcard_name %type wildcard_spec %token INT @@ -799,6 +800,11 @@ exp : ; +memspec_at_opt: + AT '>' NAME { $$ = $3; } + | { $$ = "*default*"; } + ; + opt_at: AT '(' exp ')' { $$ = $3; } | { $$ = 0; } @@ -815,10 +821,10 @@ section: NAME { ldlex_expression(); } } statement_list_opt '}' { ldlex_popstate (); ldlex_expression (); } - memspec_opt phdr_opt fill_opt + memspec_opt memspec_at_opt phdr_opt fill_opt { ldlex_popstate (); - lang_leave_output_section_statement ($13, $11, $12); + lang_leave_output_section_statement ($14, $11, $13, $12); } opt_comma | OVERLAY @@ -832,10 +838,10 @@ section: NAME { ldlex_expression(); } overlay_section '}' { ldlex_popstate (); ldlex_expression (); } - memspec_opt phdr_opt fill_opt + memspec_opt memspec_at_opt phdr_opt fill_opt { ldlex_popstate (); - lang_leave_overlay ($14, $12, $13); + lang_leave_overlay ($15, $12, $14, $13); } opt_comma | /* The GROUP case is just enough to support the gcc diff --git a/ld/ldlang.c b/ld/ldlang.c index 6913a38..a514ea0 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -682,6 +682,7 @@ lang_output_section_statement_lookup (name) 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; @@ -2695,6 +2696,43 @@ _("%X%P: section %s [%V -> %V] overlaps section %s [%V -> %V]\n"), 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 @@ -2853,37 +2891,35 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax) { 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; @@ -4259,13 +4295,22 @@ lang_float (maybe) } 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; } @@ -4644,7 +4689,8 @@ lang_leave_overlay_section (fill, phdrs) 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. */ @@ -4674,12 +4720,14 @@ lang_leave_overlay_section (fill, phdrs) 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; @@ -4688,6 +4736,11 @@ lang_leave_overlay (fill, memspec, phdrs) 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; @@ -4699,6 +4752,8 @@ lang_leave_overlay (fill, memspec, phdrs) 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; diff --git a/ld/ldlang.h b/ld/ldlang.h index 41ef5ba..068cd96 100644 --- a/ld/ldlang.h +++ b/ld/ldlang.h @@ -136,6 +136,7 @@ typedef struct lang_output_section_statement_struct flagword flags; /* Or together of all input sections */ enum section_type sectype; struct memory_region_struct *region; + struct memory_region_struct *lma_region; size_t block_value; 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_float PARAMS ((enum bfd_boolean)); 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_beginning_of PARAMS ((const char *, const char *)); @@ -475,7 +477,8 @@ extern void lang_enter_overlay_section PARAMS ((const char *)); extern void lang_leave_overlay_section PARAMS ((bfd_vma, struct lang_output_section_phdr_list *)); 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; diff --git a/ld/mri.c b/ld/mri.c index 54aaea2..d39186c 100644 --- a/ld/mri.c +++ b/ld/mri.c @@ -266,7 +266,8 @@ mri_draw_tree () } 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; } -- 2.7.4