Add support to the MSP430 linker for the automatic placement of code and data into either low or high memory regions.
gas * config/tc-msp430.c (MAX_OP_LEN): Increase to 4096. (msp430_make_init_symbols): New function. (msp430_section): Call it. (msp430_frob_section): Likewise. ld * emulparams/msp430elf.sh (TEMPLATE_NAME): Change to msp430. * scripttempl/msp430.sc (.text): Add .lower.text and .either.text. (.data): Add .lower.data and .either.data. (.bss): Add .lower.bss and .either.bss. (.rodata): Add .lower.rodata and .either.rodata. * emultempl/msp430.em: New file. Implements a new orphan placement algorithm that divides sections between lower and upper memory regions. * Makefile.am (emsp430elf.c): Depend upon msp430.em. *emsp430X.c): Likewise. * Makefine.in: Regenerate.
This commit is contained in:
parent
b76f99d702
commit
837a17b36c
8 changed files with 370 additions and 17 deletions
|
@ -1,3 +1,10 @@
|
|||
2015-05-05 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
* config/tc-msp430.c (MAX_OP_LEN): Increase to 4096.
|
||||
(msp430_make_init_symbols): New function.
|
||||
(msp430_section): Call it.
|
||||
(msp430_frob_section): Likewise.
|
||||
|
||||
2015-05-02 Max Filippov <jcmvbkbc@gmail.com>
|
||||
|
||||
* config/tc-xtensa.c (cached_fixupS, fixup_cacheS): New typedefs.
|
||||
|
|
|
@ -255,7 +255,7 @@ relax_typeS md_relax_table[] =
|
|||
};
|
||||
|
||||
|
||||
#define MAX_OP_LEN 256
|
||||
#define MAX_OP_LEN 4096
|
||||
|
||||
typedef enum msp_isa
|
||||
{
|
||||
|
@ -840,14 +840,11 @@ md_parse_option (int c, char * arg)
|
|||
|
||||
The code which initializes these sections should have a global
|
||||
label for these symbols, and should be marked with KEEP() in the
|
||||
linker script.
|
||||
*/
|
||||
static void
|
||||
msp430_section (int arg)
|
||||
{
|
||||
char * saved_ilp = input_line_pointer;
|
||||
char * name = obj_elf_section_name ();
|
||||
linker script. */
|
||||
|
||||
static void
|
||||
msp430_make_init_symbols (const char * name)
|
||||
{
|
||||
if (strncmp (name, ".bss", 4) == 0
|
||||
|| strncmp (name, ".gnu.linkonce.b.", 16) == 0)
|
||||
(void) symbol_find_or_make ("__crt0_init_bss");
|
||||
|
@ -856,6 +853,27 @@ msp430_section (int arg)
|
|||
|| strncmp (name, ".gnu.linkonce.d.", 16) == 0)
|
||||
(void) symbol_find_or_make ("__crt0_movedata");
|
||||
|
||||
/* Note - data assigned to the .either.data section may end up being
|
||||
placed in the .upper.data section if the .lower.data section is
|
||||
full. Hence the need to define the crt0 symbol. */
|
||||
if (strncmp (name, ".either.data", 12) == 0
|
||||
|| strncmp (name, ".upper.data", 11) == 0)
|
||||
(void) symbol_find_or_make ("__crt0_move_highdata");
|
||||
|
||||
/* See note about .either.data above. */
|
||||
if (strncmp (name, ".upper.bss", 10) == 0
|
||||
|| strncmp (name, ".either.bss", 11) == 0)
|
||||
(void) symbol_find_or_make ("__crt0_init_highbss");
|
||||
}
|
||||
|
||||
static void
|
||||
msp430_section (int arg)
|
||||
{
|
||||
char * saved_ilp = input_line_pointer;
|
||||
char * name = obj_elf_section_name ();
|
||||
|
||||
msp430_make_init_symbols (name);
|
||||
|
||||
input_line_pointer = saved_ilp;
|
||||
obj_elf_section (arg);
|
||||
}
|
||||
|
@ -868,13 +886,7 @@ msp430_frob_section (asection *sec)
|
|||
if (sec->size == 0)
|
||||
return;
|
||||
|
||||
if (strncmp (name, ".bss", 4) == 0
|
||||
|| strncmp (name, ".gnu.linkonce.b.", 16) == 0)
|
||||
(void) symbol_find_or_make ("__crt0_init_bss");
|
||||
|
||||
if (strncmp (name, ".data", 5) == 0
|
||||
|| strncmp (name, ".gnu.linkonce.d.", 16) == 0)
|
||||
(void) symbol_find_or_make ("__crt0_movedata");
|
||||
msp430_make_init_symbols (name);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
14
ld/ChangeLog
14
ld/ChangeLog
|
@ -1,3 +1,17 @@
|
|||
2015-05-05 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
* emulparams/msp430elf.sh (TEMPLATE_NAME): Change to msp430.
|
||||
* scripttempl/msp430.sc (.text): Add .lower.text and .either.text.
|
||||
(.data): Add .lower.data and .either.data.
|
||||
(.bss): Add .lower.bss and .either.bss.
|
||||
(.rodata): Add .lower.rodata and .either.rodata.
|
||||
* emultempl/msp430.em: New file. Implements a new orphan
|
||||
placement algorithm that divides sections between lower and upper
|
||||
memory regions.
|
||||
* Makefile.am (emsp430elf.c): Depend upon msp430.em.
|
||||
*emsp430X.c): Likewise.
|
||||
* Makefine.in: Regenerate.
|
||||
|
||||
2015-04-28 Andreas Schwab <schwab@linux-m68k.org>
|
||||
|
||||
PR ld/18344
|
||||
|
|
|
@ -1529,9 +1529,11 @@ emn10300.c: $(srcdir)/emulparams/mn10300.sh \
|
|||
$(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
|
||||
|
||||
emsp430elf.c: $(srcdir)/emulparams/msp430elf.sh \
|
||||
$(ELF_DEPS) $(srcdir)/emultempl/msp430.em \
|
||||
$(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc ${GEN_DEPENDS}
|
||||
|
||||
emsp430X.c: $(srcdir)/emulparams/msp430elf.sh $(srcdir)/emulparams/msp430X.sh \
|
||||
$(ELF_DEPS) $(srcdir)/emultempl/msp430.em \
|
||||
$(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc ${GEN_DEPENDS}
|
||||
|
||||
ends32elf.c: $(srcdir)/emulparams/nds32elf.sh \
|
||||
|
|
|
@ -3027,9 +3027,11 @@ emn10300.c: $(srcdir)/emulparams/mn10300.sh \
|
|||
$(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
|
||||
|
||||
emsp430elf.c: $(srcdir)/emulparams/msp430elf.sh \
|
||||
$(ELF_DEPS) $(srcdir)/emultempl/msp430.em \
|
||||
$(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc ${GEN_DEPENDS}
|
||||
|
||||
emsp430X.c: $(srcdir)/emulparams/msp430elf.sh $(srcdir)/emulparams/msp430X.sh \
|
||||
$(ELF_DEPS) $(srcdir)/emultempl/msp430.em \
|
||||
$(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc ${GEN_DEPENDS}
|
||||
|
||||
ends32elf.c: $(srcdir)/emulparams/nds32elf.sh \
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# This called by genscripts_extra.sh
|
||||
|
||||
SCRIPT_NAME=elf32msp430
|
||||
TEMPLATE_NAME=generic
|
||||
TEMPLATE_NAME=msp430
|
||||
EXTRA_EM_FILE=genelf
|
||||
OUTPUT_FORMAT="elf32-msp430"
|
||||
MACHINE=
|
||||
|
|
298
ld/emultempl/msp430.em
Normal file
298
ld/emultempl/msp430.em
Normal file
|
@ -0,0 +1,298 @@
|
|||
# This shell script emits a C file. -*- C -*-
|
||||
# It does some substitutions.
|
||||
fragment <<EOF
|
||||
/* This file is is generated by a shell script. DO NOT EDIT! */
|
||||
|
||||
/* Emulate the original gld for the given ${EMULATION_NAME}
|
||||
Copyright (C) 2014-2015 Free Software Foundation, Inc.
|
||||
Written by Steve Chamberlain steve@cygnus.com
|
||||
Extended for the MSP430 by Nick Clifton nickc@redhat.com
|
||||
|
||||
This file is part of the GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
MA 02110-1301, USA. */
|
||||
|
||||
#define TARGET_IS_${EMULATION_NAME}
|
||||
|
||||
#include "sysdep.h"
|
||||
#include "bfd.h"
|
||||
#include "bfdlink.h"
|
||||
|
||||
#include "ld.h"
|
||||
#include "ldmain.h"
|
||||
#include "ldmisc.h"
|
||||
#include "ldexp.h"
|
||||
#include "ldlang.h"
|
||||
#include "ldfile.h"
|
||||
#include "ldemul.h"
|
||||
#include "libiberty.h"
|
||||
|
||||
EOF
|
||||
|
||||
# Import any needed special functions and/or overrides.
|
||||
#
|
||||
if test -n "$EXTRA_EM_FILE" ; then
|
||||
source_em ${srcdir}/emultempl/${EXTRA_EM_FILE}.em
|
||||
fi
|
||||
|
||||
if test x"$LDEMUL_BEFORE_PARSE" != xgld"$EMULATION_NAME"_before_parse; then
|
||||
fragment <<EOF
|
||||
|
||||
static void
|
||||
gld${EMULATION_NAME}_before_parse (void)
|
||||
{
|
||||
#ifndef TARGET_ /* I.e., if not generic. */
|
||||
ldfile_set_output_arch ("`echo ${ARCH}`", bfd_arch_unknown);
|
||||
#endif /* not TARGET_ */
|
||||
|
||||
/* The MSP430 port *needs* linker relaxtion in order to cope with large
|
||||
functions where conditional branches do not fit into a +/- 1024 byte range. */
|
||||
if (! link_info.relocatable)
|
||||
TARGET_ENABLE_RELAXATION;
|
||||
}
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
if test x"$LDEMUL_GET_SCRIPT" != xgld"$EMULATION_NAME"_get_script; then
|
||||
fragment <<EOF
|
||||
|
||||
static char *
|
||||
gld${EMULATION_NAME}_get_script (int *isfile)
|
||||
EOF
|
||||
|
||||
if test x"$COMPILE_IN" = xyes
|
||||
then
|
||||
# Scripts compiled in.
|
||||
|
||||
# sed commands to quote an ld script as a C string.
|
||||
sc="-f stringify.sed"
|
||||
|
||||
fragment <<EOF
|
||||
{
|
||||
*isfile = 0;
|
||||
|
||||
if (link_info.relocatable && config.build_constructors)
|
||||
return
|
||||
EOF
|
||||
sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c
|
||||
echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c
|
||||
sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c
|
||||
echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c
|
||||
sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c
|
||||
echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c
|
||||
sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c
|
||||
echo ' ; else return' >> e${EMULATION_NAME}.c
|
||||
sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c
|
||||
echo '; }' >> e${EMULATION_NAME}.c
|
||||
|
||||
else
|
||||
# Scripts read from the filesystem.
|
||||
|
||||
fragment <<EOF
|
||||
{
|
||||
*isfile = 1;
|
||||
|
||||
if (link_info.relocatable && config.build_constructors)
|
||||
return "ldscripts/${EMULATION_NAME}.xu";
|
||||
else if (link_info.relocatable)
|
||||
return "ldscripts/${EMULATION_NAME}.xr";
|
||||
else if (!config.text_read_only)
|
||||
return "ldscripts/${EMULATION_NAME}.xbn";
|
||||
else if (!config.magic_demand_paged)
|
||||
return "ldscripts/${EMULATION_NAME}.xn";
|
||||
else
|
||||
return "ldscripts/${EMULATION_NAME}.x";
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then
|
||||
fragment <<EOF
|
||||
|
||||
/* Helper function for place_orphan that computes the size
|
||||
of sections already mapped to the given statement. */
|
||||
|
||||
static bfd_size_type
|
||||
scan_children (lang_statement_union_type * l)
|
||||
{
|
||||
bfd_size_type amount = 0;
|
||||
|
||||
while (l != NULL)
|
||||
{
|
||||
switch (l->header.type)
|
||||
{
|
||||
case lang_input_section_enum:
|
||||
if (l->input_section.section->flags & SEC_ALLOC)
|
||||
amount += l->input_section.section->size;
|
||||
break;
|
||||
|
||||
case lang_constructors_statement_enum:
|
||||
case lang_assignment_statement_enum:
|
||||
break;
|
||||
|
||||
case lang_wild_statement_enum:
|
||||
amount += scan_children (l->wild_statement.children.head);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf (stderr, "msp430 orphan placer: unhandled lang type %d\n", l->header.type);
|
||||
break;
|
||||
}
|
||||
|
||||
l = l->header.next;
|
||||
}
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
/* Place an orphan section. We use this to put .either sections
|
||||
into either their lower or their upper equivalents. */
|
||||
|
||||
static lang_output_section_statement_type *
|
||||
gld${EMULATION_NAME}_place_orphan (asection * s,
|
||||
const char * secname,
|
||||
int constraint)
|
||||
{
|
||||
char * lower_name;
|
||||
char * upper_name;
|
||||
char * name;
|
||||
lang_output_section_statement_type * lower;
|
||||
lang_output_section_statement_type * upper;
|
||||
lang_output_section_statement_type * os;
|
||||
|
||||
if ((s->flags & SEC_ALLOC) == 0)
|
||||
return NULL;
|
||||
|
||||
if (link_info.relocatable)
|
||||
return NULL;
|
||||
|
||||
/* If constraints are involved let the linker handle the placement normally. */
|
||||
if (constraint != 0)
|
||||
return NULL;
|
||||
|
||||
/* We only need special handling for .either sections. */
|
||||
if (strncmp (secname, ".either.", 8) != 0)
|
||||
return NULL;
|
||||
|
||||
/* Skip the .either prefix. */
|
||||
secname += 7;
|
||||
|
||||
/* Compute the names of the corresponding upper and lower
|
||||
sections. If the input section name contains another period,
|
||||
only use the part of the name before the second dot. */
|
||||
if (strchr (secname + 1, '.') != NULL)
|
||||
{
|
||||
name = ACONCAT ((secname, NULL));
|
||||
|
||||
* strchr (name + 1, '.') = 0;
|
||||
}
|
||||
else
|
||||
name = (char *) secname;
|
||||
|
||||
lower_name = ACONCAT ((".lower", name, NULL));
|
||||
upper_name = ACONCAT ((".upper", name, NULL));
|
||||
|
||||
/* Find the corresponding lower and upper sections. */
|
||||
lower = lang_output_section_find (lower_name);
|
||||
upper = lang_output_section_find (upper_name);
|
||||
/* If the upper section does not exist, try again without the suffix. */
|
||||
if (upper == NULL)
|
||||
upper = lang_output_section_find (name);
|
||||
|
||||
if (lower == NULL)
|
||||
{
|
||||
os = upper;
|
||||
if (upper == NULL)
|
||||
{
|
||||
einfo ("%P: error: no section named %s or %s in linker script\n", lower_name, upper_name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (upper == NULL)
|
||||
os = lower;
|
||||
else if (lower->region == NULL)
|
||||
os = lower;
|
||||
/* If the section is too big for the region containing
|
||||
the lower section then do not even try to use it. */
|
||||
else if (lower->region->length < s->size)
|
||||
os = upper;
|
||||
else
|
||||
{
|
||||
bfd_size_type amount = 0;
|
||||
struct lang_output_section_statement_struct * p;
|
||||
|
||||
amount += scan_children (lower->children.head);
|
||||
|
||||
/* Also check forwards for other statements assigned to the same region. */
|
||||
for (p = lower->next; p != NULL; p = p->next)
|
||||
if (p->region == lower->region)
|
||||
amount += scan_children (p->children.head);
|
||||
|
||||
/* Scan backwards as well. */
|
||||
for (p = lower->prev; p != NULL; p = p->prev)
|
||||
if (p->region == lower->region)
|
||||
amount += scan_children (p->children.head);
|
||||
|
||||
if (amount + s->size >= lower->region->length)
|
||||
os = upper;
|
||||
else
|
||||
os = lower;
|
||||
}
|
||||
|
||||
lang_add_section (& os->children, s, NULL, os);
|
||||
return os;
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
|
||||
fragment <<EOF
|
||||
|
||||
struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
|
||||
{
|
||||
${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse},
|
||||
${LDEMUL_SYSLIB-syslib_default},
|
||||
${LDEMUL_HLL-hll_default},
|
||||
${LDEMUL_AFTER_PARSE-after_parse_default},
|
||||
${LDEMUL_AFTER_OPEN-after_open_default},
|
||||
${LDEMUL_AFTER_ALLOCATION-after_allocation_default},
|
||||
${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default},
|
||||
${LDEMUL_CHOOSE_TARGET-ldemul_default_target},
|
||||
${LDEMUL_BEFORE_ALLOCATION-before_allocation_default},
|
||||
${LDEMUL_GET_SCRIPT-gld${EMULATION_NAME}_get_script},
|
||||
"${EMULATION_NAME}",
|
||||
"${OUTPUT_FORMAT}",
|
||||
${LDEMUL_FINISH-finish_default},
|
||||
${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL},
|
||||
${LDEMUL_OPEN_DYNAMIC_ARCHIVE-NULL},
|
||||
${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan},
|
||||
${LDEMUL_SET_SYMBOLS-NULL},
|
||||
${LDEMUL_PARSE_ARGS-NULL},
|
||||
${LDEMUL_ADD_OPTIONS-NULL},
|
||||
${LDEMUL_HANDLE_OPTION-NULL},
|
||||
${LDEMUL_UNRECOGNIZED_FILE-NULL},
|
||||
${LDEMUL_LIST_OPTIONS-NULL},
|
||||
${LDEMUL_RECOGNIZED_FILE-NULL},
|
||||
${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
|
||||
${LDEMUL_NEW_VERS_PATTERN-NULL},
|
||||
${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL}
|
||||
};
|
||||
EOF
|
||||
#
|
||||
# Local Variables:
|
||||
# mode: c
|
||||
# End:
|
|
@ -153,6 +153,9 @@ SECTIONS
|
|||
${CONSTRUCTING+ *(.dtors) }
|
||||
${CONSTRUCTING+ __dtors_end = . ; }
|
||||
|
||||
${RELOCATING+. = ALIGN(2);}
|
||||
*(.lower.text.* .lower.text)
|
||||
|
||||
${RELOCATING+. = ALIGN(2);}
|
||||
*(.text)
|
||||
${RELOCATING+. = ALIGN(2);}
|
||||
|
@ -160,6 +163,8 @@ SECTIONS
|
|||
${RELOCATING+. = ALIGN(2);}
|
||||
*(.text:*)
|
||||
|
||||
*(.either.text.* .either.text)
|
||||
|
||||
${RELOCATING+. = ALIGN(2);}
|
||||
*(SORT_NONE(.fini9))
|
||||
*(SORT_NONE(.fini8))
|
||||
|
@ -178,11 +183,15 @@ SECTIONS
|
|||
|
||||
.rodata :
|
||||
{
|
||||
${RELOCATING+. = ALIGN(2);}
|
||||
*(.lower.rodata.* .lower.rodata)
|
||||
|
||||
. = ALIGN(2);
|
||||
*(.plt)
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.* .const .const:*)
|
||||
*(.rodata1)
|
||||
|
||||
*(.either.rodata.*) *(.either.rodata)
|
||||
*(.eh_frame_hdr)
|
||||
KEEP (*(.eh_frame))
|
||||
|
||||
|
@ -242,23 +251,32 @@ SECTIONS
|
|||
*(.data.rel.ro.local) *(.data.rel.ro*)
|
||||
*(.dynamic)
|
||||
|
||||
${RELOCATING+. = ALIGN(2);}
|
||||
*(.lower.data.* .lower.data)
|
||||
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
*(.gnu.linkonce.d*)
|
||||
KEEP (*(.gnu.linkonce.d.*personality*))
|
||||
*(.data1)
|
||||
|
||||
*(.either.data.* .either.data)
|
||||
|
||||
*(.got.plt) *(.got)
|
||||
${RELOCATING+. = ALIGN(2);}
|
||||
*(.sdata .sdata.* .gnu.linkonce.s.*)
|
||||
${RELOCATING+. = ALIGN(2);}
|
||||
${RELOCATING+ _edata = . ; }
|
||||
} ${RELOCATING+ > data ${RELOCATING+AT> text}}
|
||||
|
||||
|
||||
.bss ${RELOCATING+ SIZEOF(.data) + ADDR(.data)} :
|
||||
{
|
||||
${RELOCATING+. = ALIGN(2);}
|
||||
${RELOCATING+ PROVIDE (__bss_start = .) ; }
|
||||
*(.lower.bss.* .lower.bss)
|
||||
${RELOCATING+. = ALIGN(2);}
|
||||
*(.bss)
|
||||
*(.either.bss.* .either.bss)
|
||||
*(COMMON)
|
||||
${RELOCATING+ PROVIDE (__bss_end = .) ; }
|
||||
${RELOCATING+ _end = . ; }
|
||||
|
|
Loading…
Reference in a new issue