mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-22 00:33:33 +08:00
fd3619828e
This large patch removes the unnecessary bfd parameter from various bfd section macros and functions. The bfd is hardly ever used and if needed for the bfd_set_section_* or bfd_rename_section functions can be found via section->owner except for the com, und, abs, and ind std_section special sections. Those sections shouldn't be modified anyway. The patch also removes various bfd_get_section_<field> macros, replacing their use with bfd_section_<field>, and adds bfd_set_section_lma. I've also fixed a minor bug in gas where compressed section renaming was done directly rather than calling bfd_rename_section. This would have broken bfd_get_section_by_name and similar functions, but that hardly mattered at such a late stage in gas processing. bfd/ * bfd-in.h (bfd_get_section_name, bfd_get_section_vma), (bfd_get_section_lma, bfd_get_section_alignment), (bfd_get_section_size, bfd_get_section_flags), (bfd_get_section_userdata): Delete. (bfd_section_name, bfd_section_size, bfd_section_vma), (bfd_section_lma, bfd_section_alignment): Lose bfd parameter. (bfd_section_flags, bfd_section_userdata): New. (bfd_is_com_section): Rename parameter. * section.c (bfd_set_section_userdata, bfd_set_section_vma), (bfd_set_section_alignment, bfd_set_section_flags, bfd_rename_section), (bfd_set_section_size): Delete bfd parameter, rename section parameter. (bfd_set_section_lma): New. * bfd-in2.h: Regenerate. * mach-o.c (bfd_mach_o_init_section_from_mach_o): Delete bfd param, update callers. * aoutx.h, * bfd.c, * coff-alpha.c, * coff-arm.c, * coff-mips.c, * coff64-rs6000.c, * coffcode.h, * coffgen.c, * cofflink.c, * compress.c, * ecoff.c, * elf-eh-frame.c, * elf-hppa.h, * elf-ifunc.c, * elf-m10200.c, * elf-m10300.c, * elf-properties.c, * elf-s390-common.c, * elf-vxworks.c, * elf.c, * elf32-arc.c, * elf32-arm.c, * elf32-avr.c, * elf32-bfin.c, * elf32-cr16.c, * elf32-cr16c.c, * elf32-cris.c, * elf32-crx.c, * elf32-csky.c, * elf32-d10v.c, * elf32-epiphany.c, * elf32-fr30.c, * elf32-frv.c, * elf32-ft32.c, * elf32-h8300.c, * elf32-hppa.c, * elf32-i386.c, * elf32-ip2k.c, * elf32-iq2000.c, * elf32-lm32.c, * elf32-m32c.c, * elf32-m32r.c, * elf32-m68hc1x.c, * elf32-m68k.c, * elf32-mcore.c, * elf32-mep.c, * elf32-metag.c, * elf32-microblaze.c, * elf32-moxie.c, * elf32-msp430.c, * elf32-mt.c, * elf32-nds32.c, * elf32-nios2.c, * elf32-or1k.c, * elf32-ppc.c, * elf32-pru.c, * elf32-rl78.c, * elf32-rx.c, * elf32-s390.c, * elf32-score.c, * elf32-score7.c, * elf32-sh.c, * elf32-spu.c, * elf32-tic6x.c, * elf32-tilepro.c, * elf32-v850.c, * elf32-vax.c, * elf32-visium.c, * elf32-xstormy16.c, * elf32-xtensa.c, * elf64-alpha.c, * elf64-bpf.c, * elf64-hppa.c, * elf64-ia64-vms.c, * elf64-mmix.c, * elf64-ppc.c, * elf64-s390.c, * elf64-sparc.c, * elf64-x86-64.c, * elflink.c, * elfnn-aarch64.c, * elfnn-ia64.c, * elfnn-riscv.c, * elfxx-aarch64.c, * elfxx-mips.c, * elfxx-sparc.c, * elfxx-tilegx.c, * elfxx-x86.c, * i386msdos.c, * linker.c, * mach-o.c, * mmo.c, * opncls.c, * pdp11.c, * pei-x86_64.c, * peicode.h, * reloc.c, * section.c, * syms.c, * vms-alpha.c, * xcofflink.c: Update throughout for bfd section macro and function changes. binutils/ * addr2line.c, * bucomm.c, * coffgrok.c, * dlltool.c, * nm.c, * objcopy.c, * objdump.c, * od-elf32_avr.c, * od-macho.c, * od-xcoff.c, * prdbg.c, * rdcoff.c, * rddbg.c, * rescoff.c, * resres.c, * size.c, * srconv.c, * strings.c, * windmc.c: Update throughout for bfd section macro and function changes. gas/ * as.c, * as.h, * dw2gencfi.c, * dwarf2dbg.c, * ecoff.c, * read.c, * stabs.c, * subsegs.c, * subsegs.h, * write.c, * config/obj-coff-seh.c, * config/obj-coff.c, * config/obj-ecoff.c, * config/obj-elf.c, * config/obj-macho.c, * config/obj-som.c, * config/tc-aarch64.c, * config/tc-alpha.c, * config/tc-arc.c, * config/tc-arm.c, * config/tc-avr.c, * config/tc-bfin.c, * config/tc-bpf.c, * config/tc-d10v.c, * config/tc-d30v.c, * config/tc-epiphany.c, * config/tc-fr30.c, * config/tc-frv.c, * config/tc-h8300.c, * config/tc-hppa.c, * config/tc-i386.c, * config/tc-ia64.c, * config/tc-ip2k.c, * config/tc-iq2000.c, * config/tc-lm32.c, * config/tc-m32c.c, * config/tc-m32r.c, * config/tc-m68hc11.c, * config/tc-mep.c, * config/tc-microblaze.c, * config/tc-mips.c, * config/tc-mmix.c, * config/tc-mn10200.c, * config/tc-mn10300.c, * config/tc-msp430.c, * config/tc-mt.c, * config/tc-nds32.c, * config/tc-or1k.c, * config/tc-ppc.c, * config/tc-pru.c, * config/tc-rl78.c, * config/tc-rx.c, * config/tc-s12z.c, * config/tc-s390.c, * config/tc-score.c, * config/tc-score7.c, * config/tc-sh.c, * config/tc-sparc.c, * config/tc-spu.c, * config/tc-tic4x.c, * config/tc-tic54x.c, * config/tc-tic6x.c, * config/tc-tilegx.c, * config/tc-tilepro.c, * config/tc-v850.c, * config/tc-visium.c, * config/tc-wasm32.c, * config/tc-xc16x.c, * config/tc-xgate.c, * config/tc-xstormy16.c, * config/tc-xtensa.c, * config/tc-z8k.c: Update throughout for bfd section macro and function changes. * write.c (compress_debug): Use bfd_rename_section. gdb/ * aarch64-linux-tdep.c, * arm-tdep.c, * auto-load.c, * coff-pe-read.c, * coffread.c, * corelow.c, * dbxread.c, * dicos-tdep.c, * dwarf2-frame.c, * dwarf2read.c, * elfread.c, * exec.c, * fbsd-tdep.c, * gcore.c, * gdb_bfd.c, * gdb_bfd.h, * hppa-tdep.c, * i386-cygwin-tdep.c, * i386-fbsd-tdep.c, * i386-linux-tdep.c, * jit.c, * linux-tdep.c, * machoread.c, * maint.c, * mdebugread.c, * minidebug.c, * mips-linux-tdep.c, * mips-sde-tdep.c, * mips-tdep.c, * mipsread.c, * nto-tdep.c, * objfiles.c, * objfiles.h, * osabi.c, * ppc-linux-tdep.c, * ppc64-tdep.c, * record-btrace.c, * record-full.c, * remote.c, * rs6000-aix-tdep.c, * rs6000-tdep.c, * s390-linux-tdep.c, * s390-tdep.c, * solib-aix.c, * solib-dsbt.c, * solib-frv.c, * solib-spu.c, * solib-svr4.c, * solib-target.c, * spu-linux-nat.c, * spu-tdep.c, * symfile-mem.c, * symfile.c, * symmisc.c, * symtab.c, * target.c, * windows-nat.c, * xcoffread.c, * cli/cli-dump.c, * compile/compile-object-load.c, * mi/mi-interp.c: Update throughout for bfd section macro and function changes. * gcore (gcore_create_callback): Use bfd_set_section_lma. * spu-tdep.c (spu_overlay_new_objfile): Likewise. gprof/ * corefile.c, * symtab.c: Update throughout for bfd section macro and function changes. ld/ * ldcref.c, * ldctor.c, * ldelf.c, * ldlang.c, * pe-dll.c, * emultempl/aarch64elf.em, * emultempl/aix.em, * emultempl/armcoff.em, * emultempl/armelf.em, * emultempl/cr16elf.em, * emultempl/cskyelf.em, * emultempl/m68hc1xelf.em, * emultempl/m68kelf.em, * emultempl/mipself.em, * emultempl/mmix-elfnmmo.em, * emultempl/mmo.em, * emultempl/msp430.em, * emultempl/nios2elf.em, * emultempl/pe.em, * emultempl/pep.em, * emultempl/ppc64elf.em, * emultempl/xtensaelf.em: Update throughout for bfd section macro and function changes. libctf/ * ctf-open-bfd.c: Update throughout for bfd section macro changes. opcodes/ * arc-ext.c: Update throughout for bfd section macro changes. sim/ * common/sim-load.c, * common/sim-utils.c, * cris/sim-if.c, * erc32/func.c, * lm32/sim-if.c, * m32c/load.c, * m32c/trace.c, * m68hc11/interp.c, * ppc/hw_htab.c, * ppc/hw_init.c, * rl78/load.c, * rl78/trace.c, * rx/gdb-if.c, * rx/load.c, * rx/trace.c: Update throughout for bfd section macro changes.
854 lines
23 KiB
Plaintext
854 lines
23 KiB
Plaintext
# 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-2019 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 "getopt.h"
|
||
#include "ldmain.h"
|
||
#include "ldmisc.h"
|
||
#include "ldexp.h"
|
||
#include "ldlang.h"
|
||
#include "ldfile.h"
|
||
#include "ldemul.h"
|
||
#include "libiberty.h"
|
||
#include <ldgram.h>
|
||
|
||
enum regions
|
||
{
|
||
REGION_NONE = 0,
|
||
REGION_LOWER,
|
||
REGION_UPPER,
|
||
REGION_EITHER = 3,
|
||
};
|
||
|
||
enum either_placement_stage
|
||
{
|
||
LOWER_TO_UPPER,
|
||
UPPER_TO_LOWER,
|
||
};
|
||
|
||
enum { ROM, RAM };
|
||
|
||
static int data_region = REGION_NONE;
|
||
static int code_region = REGION_NONE;
|
||
static bfd_boolean disable_sec_transformation = FALSE;
|
||
|
||
#define MAX_PREFIX_LENGTH 7
|
||
|
||
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 (!bfd_link_relocatable (&link_info))
|
||
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 (bfd_link_relocatable (&link_info) && config.build_constructors)
|
||
return
|
||
EOF
|
||
sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c
|
||
echo ' ; else if (bfd_link_relocatable (&link_info)) 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 (bfd_link_relocatable (&link_info) && config.build_constructors)
|
||
return "ldscripts/${EMULATION_NAME}.xu";
|
||
else if (bfd_link_relocatable (&link_info))
|
||
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
|
||
|
||
static unsigned int
|
||
data_statement_size (lang_data_statement_type *d)
|
||
{
|
||
unsigned int size = 0;
|
||
switch (d->type)
|
||
{
|
||
case QUAD:
|
||
case SQUAD:
|
||
size = QUAD_SIZE;
|
||
break;
|
||
case LONG:
|
||
size = LONG_SIZE;
|
||
break;
|
||
case SHORT:
|
||
size = SHORT_SIZE;
|
||
break;
|
||
case BYTE:
|
||
size = BYTE_SIZE;
|
||
break;
|
||
default:
|
||
einfo (_("%P: error: unhandled data_statement size\n"));
|
||
FAIL ();
|
||
}
|
||
return size;
|
||
}
|
||
|
||
/* 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:
|
||
case lang_padding_statement_enum:
|
||
break;
|
||
|
||
case lang_wild_statement_enum:
|
||
amount += scan_children (l->wild_statement.children.head);
|
||
break;
|
||
|
||
case lang_data_statement_enum:
|
||
amount += data_statement_size (&l->data_statement);
|
||
break;
|
||
|
||
default:
|
||
fprintf (stderr, "msp430 orphan placer: unhandled lang type %d\n", l->header.type);
|
||
break;
|
||
}
|
||
|
||
l = l->header.next;
|
||
}
|
||
|
||
return amount;
|
||
}
|
||
|
||
#define WARN_UPPER 0
|
||
#define WARN_LOWER 1
|
||
#define WARN_TEXT 0
|
||
#define WARN_DATA 1
|
||
#define WARN_BSS 2
|
||
#define WARN_RODATA 3
|
||
|
||
/* Warn only once per output section.
|
||
* NAME starts with ".upper." or ".lower.". */
|
||
static void
|
||
warn_no_output_section (const char *name)
|
||
{
|
||
static bfd_boolean warned[2][4] = {{FALSE, FALSE, FALSE, FALSE},
|
||
{FALSE, FALSE, FALSE, FALSE}};
|
||
int i = WARN_LOWER;
|
||
|
||
if (strncmp (name, ".upper.", 7) == 0)
|
||
i = WARN_UPPER;
|
||
|
||
if (!warned[i][WARN_TEXT] && strcmp (name + 6, ".text") == 0)
|
||
warned[i][WARN_TEXT] = TRUE;
|
||
else if (!warned[i][WARN_DATA] && strcmp (name + 6, ".data") == 0)
|
||
warned[i][WARN_DATA] = TRUE;
|
||
else if (!warned[i][WARN_BSS] && strcmp (name + 6, ".bss") == 0)
|
||
warned[i][WARN_BSS] = TRUE;
|
||
else if (!warned[i][WARN_RODATA] && strcmp (name + 6, ".rodata") == 0)
|
||
warned[i][WARN_RODATA] = TRUE;
|
||
else
|
||
return;
|
||
einfo ("%P: warning: no input section rule matches %s in linker script\n",
|
||
name);
|
||
}
|
||
|
||
|
||
/* 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;
|
||
char * buf = NULL;
|
||
lang_output_section_statement_type * lower;
|
||
lang_output_section_statement_type * upper;
|
||
|
||
if ((s->flags & SEC_ALLOC) == 0)
|
||
return NULL;
|
||
|
||
if (bfd_link_relocatable (&link_info))
|
||
return NULL;
|
||
|
||
/* If constraints are involved let the linker handle the placement normally. */
|
||
if (constraint != 0)
|
||
return NULL;
|
||
|
||
if (strncmp (secname, ".upper.", 7) == 0
|
||
|| strncmp (secname, ".lower.", 7) == 0)
|
||
{
|
||
warn_no_output_section (secname);
|
||
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)
|
||
{
|
||
buf = name = xstrdup (secname);
|
||
|
||
* strchr (name + 1, '.') = 0;
|
||
}
|
||
else
|
||
name = (char *) secname;
|
||
|
||
lower_name = concat (".lower", name, NULL);
|
||
upper_name = concat (".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 (lower == NULL && upper == NULL)
|
||
{
|
||
einfo (_("%P: error: no section named %s or %s in linker script\n"),
|
||
lower_name, upper_name);
|
||
goto end;
|
||
}
|
||
else if (lower == NULL)
|
||
{
|
||
lower = lang_output_section_find (name);
|
||
if (lower == NULL)
|
||
{
|
||
einfo (_("%P: error: no section named %s in linker script\n"), name);
|
||
goto end;
|
||
}
|
||
}
|
||
|
||
/* Always place orphaned sections in lower. Optimal placement of either
|
||
sections is performed later, once section sizes have been finalized. */
|
||
lang_add_section (& lower->children, s, NULL, lower);
|
||
end:
|
||
free (upper_name);
|
||
free (lower_name);
|
||
if (buf)
|
||
free (buf);
|
||
return lower;
|
||
}
|
||
EOF
|
||
fi
|
||
|
||
fragment <<EOF
|
||
|
||
static bfd_boolean
|
||
change_output_section (lang_statement_union_type ** head,
|
||
asection *s,
|
||
lang_output_section_statement_type * new_output_section)
|
||
{
|
||
asection *is;
|
||
lang_statement_union_type * prev = NULL;
|
||
lang_statement_union_type * curr;
|
||
|
||
curr = *head;
|
||
while (curr != NULL)
|
||
{
|
||
switch (curr->header.type)
|
||
{
|
||
case lang_input_section_enum:
|
||
is = curr->input_section.section;
|
||
if (is == s)
|
||
{
|
||
s->output_section = NULL;
|
||
lang_add_section (& (new_output_section->children), s, NULL,
|
||
new_output_section);
|
||
/* Remove the section from the old output section. */
|
||
if (prev == NULL)
|
||
*head = curr->header.next;
|
||
else
|
||
prev->header.next = curr->header.next;
|
||
return TRUE;
|
||
}
|
||
break;
|
||
case lang_wild_statement_enum:
|
||
if (change_output_section (&(curr->wild_statement.children.head),
|
||
s, new_output_section))
|
||
return TRUE;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
prev = curr;
|
||
curr = curr->header.next;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
static void
|
||
add_region_prefix (bfd *abfd ATTRIBUTE_UNUSED, asection *s,
|
||
void *unused ATTRIBUTE_UNUSED)
|
||
{
|
||
const char *curr_name = bfd_section_name (s);
|
||
int region = REGION_NONE;
|
||
|
||
if (strncmp (curr_name, ".text", 5) == 0)
|
||
region = code_region;
|
||
else if (strncmp (curr_name, ".data", 5) == 0)
|
||
region = data_region;
|
||
else if (strncmp (curr_name, ".bss", 4) == 0)
|
||
region = data_region;
|
||
else if (strncmp (curr_name, ".rodata", 7) == 0)
|
||
region = data_region;
|
||
else
|
||
return;
|
||
|
||
switch (region)
|
||
{
|
||
case REGION_NONE:
|
||
break;
|
||
case REGION_UPPER:
|
||
bfd_rename_section (s, concat (".upper", curr_name, NULL));
|
||
break;
|
||
case REGION_LOWER:
|
||
bfd_rename_section (s, concat (".lower", curr_name, NULL));
|
||
break;
|
||
case REGION_EITHER:
|
||
s->name = concat (".either", curr_name, NULL);
|
||
break;
|
||
default:
|
||
/* Unreachable. */
|
||
FAIL ();
|
||
break;
|
||
}
|
||
}
|
||
|
||
static void
|
||
msp430_elf_after_open (void)
|
||
{
|
||
bfd *abfd;
|
||
|
||
gld${EMULATION_NAME}_after_open ();
|
||
|
||
/* If neither --code-region or --data-region have been passed, do not
|
||
transform sections names. */
|
||
if ((code_region == REGION_NONE && data_region == REGION_NONE)
|
||
|| disable_sec_transformation)
|
||
return;
|
||
|
||
for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link.next)
|
||
bfd_map_over_sections (abfd, add_region_prefix, NULL);
|
||
}
|
||
|
||
#define OPTION_CODE_REGION 321
|
||
#define OPTION_DATA_REGION (OPTION_CODE_REGION + 1)
|
||
#define OPTION_DISABLE_TRANS (OPTION_CODE_REGION + 2)
|
||
|
||
static void
|
||
gld${EMULATION_NAME}_add_options
|
||
(int ns, char **shortopts, int nl, struct option **longopts,
|
||
int nrl ATTRIBUTE_UNUSED, struct option **really_longopts ATTRIBUTE_UNUSED)
|
||
{
|
||
static const char xtra_short[] = { };
|
||
|
||
static const struct option xtra_long[] =
|
||
{
|
||
{ "code-region", required_argument, NULL, OPTION_CODE_REGION },
|
||
{ "data-region", required_argument, NULL, OPTION_DATA_REGION },
|
||
{ "disable-sec-transformation", no_argument, NULL,
|
||
OPTION_DISABLE_TRANS },
|
||
{ NULL, no_argument, NULL, 0 }
|
||
};
|
||
|
||
*shortopts = (char *) xrealloc (*shortopts, ns + sizeof (xtra_short));
|
||
memcpy (*shortopts + ns, &xtra_short, sizeof (xtra_short));
|
||
*longopts = (struct option *)
|
||
xrealloc (*longopts, nl * sizeof (struct option) + sizeof (xtra_long));
|
||
memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long));
|
||
}
|
||
|
||
static void
|
||
gld${EMULATION_NAME}_list_options (FILE * file)
|
||
{
|
||
fprintf (file, _(" --code-region={either,lower,upper,none}\n\
|
||
Transform .text* sections to {either,lower,upper,none}.text* sections\n"));
|
||
fprintf (file, _(" --data-region={either,lower,upper,none}\n\
|
||
Transform .data*, .rodata* and .bss* sections to\n\
|
||
{either,lower,upper,none}.{bss,data,rodata}* sections\n"));
|
||
fprintf (file, _(" --disable-sec-transformation\n\
|
||
Disable transformation of .{text,data,bss,rodata}* sections to\n\
|
||
add the {either,lower,upper,none} prefixes\n"));
|
||
}
|
||
|
||
static bfd_boolean
|
||
gld${EMULATION_NAME}_handle_option (int optc)
|
||
{
|
||
switch (optc)
|
||
{
|
||
case OPTION_CODE_REGION:
|
||
if (strcmp (optarg, "upper") == 0)
|
||
code_region = REGION_UPPER;
|
||
else if (strcmp (optarg, "lower") == 0)
|
||
code_region = REGION_LOWER;
|
||
else if (strcmp (optarg, "either") == 0)
|
||
code_region = REGION_EITHER;
|
||
else if (strcmp (optarg, "none") == 0)
|
||
code_region = REGION_NONE;
|
||
else if (strlen (optarg) == 0)
|
||
{
|
||
einfo (_("%P: --code-region requires an argument: "
|
||
"{upper,lower,either,none}\n"));
|
||
return FALSE;
|
||
}
|
||
else
|
||
{
|
||
einfo (_("%P: error: unrecognized argument to --code-region= option: "
|
||
"\"%s\"\n"), optarg);
|
||
return FALSE;
|
||
}
|
||
break;
|
||
|
||
case OPTION_DATA_REGION:
|
||
if (strcmp (optarg, "upper") == 0)
|
||
data_region = REGION_UPPER;
|
||
else if (strcmp (optarg, "lower") == 0)
|
||
data_region = REGION_LOWER;
|
||
else if (strcmp (optarg, "either") == 0)
|
||
data_region = REGION_EITHER;
|
||
else if (strcmp (optarg, "none") == 0)
|
||
data_region = REGION_NONE;
|
||
else if (strlen (optarg) == 0)
|
||
{
|
||
einfo (_("%P: --data-region requires an argument: "
|
||
"{upper,lower,either,none}\n"));
|
||
return FALSE;
|
||
}
|
||
else
|
||
{
|
||
einfo (_("%P: error: unrecognized argument to --data-region= option: "
|
||
"\"%s\"\n"), optarg);
|
||
return FALSE;
|
||
}
|
||
break;
|
||
|
||
case OPTION_DISABLE_TRANS:
|
||
disable_sec_transformation = TRUE;
|
||
break;
|
||
|
||
default:
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
static void
|
||
eval_upper_either_sections (bfd *abfd ATTRIBUTE_UNUSED,
|
||
asection *s, void *data)
|
||
{
|
||
const char * base_sec_name;
|
||
const char * curr_name;
|
||
char * either_name;
|
||
int curr_region;
|
||
|
||
lang_output_section_statement_type * lower;
|
||
lang_output_section_statement_type * upper;
|
||
static bfd_size_type *lower_size = 0;
|
||
static bfd_size_type *upper_size = 0;
|
||
static bfd_size_type lower_size_rom = 0;
|
||
static bfd_size_type lower_size_ram = 0;
|
||
static bfd_size_type upper_size_rom = 0;
|
||
static bfd_size_type upper_size_ram = 0;
|
||
|
||
if ((s->flags & SEC_ALLOC) == 0)
|
||
return;
|
||
if (bfd_link_relocatable (&link_info))
|
||
return;
|
||
|
||
base_sec_name = (const char *) data;
|
||
curr_name = bfd_section_name (s);
|
||
|
||
/* Only concerned with .either input sections in the upper output section. */
|
||
either_name = concat (".either", base_sec_name, NULL);
|
||
if (strncmp (curr_name, either_name, strlen (either_name)) != 0
|
||
|| strncmp (s->output_section->name, ".upper", 6) != 0)
|
||
goto end;
|
||
|
||
lower = lang_output_section_find (concat (".lower", base_sec_name, NULL));
|
||
upper = lang_output_section_find (concat (".upper", base_sec_name, NULL));
|
||
|
||
if (upper == NULL || upper->region == NULL)
|
||
goto end;
|
||
else if (lower == NULL)
|
||
lower = lang_output_section_find (base_sec_name);
|
||
if (lower == NULL || lower->region == NULL)
|
||
goto end;
|
||
|
||
if (strcmp (base_sec_name, ".text") == 0
|
||
|| strcmp (base_sec_name, ".rodata") == 0)
|
||
curr_region = ROM;
|
||
else
|
||
curr_region = RAM;
|
||
|
||
if (curr_region == ROM)
|
||
{
|
||
if (lower_size_rom == 0)
|
||
{
|
||
lower_size_rom = lower->region->current - lower->region->origin;
|
||
upper_size_rom = upper->region->current - upper->region->origin;
|
||
}
|
||
lower_size = &lower_size_rom;
|
||
upper_size = &upper_size_rom;
|
||
}
|
||
else if (curr_region == RAM)
|
||
{
|
||
if (lower_size_ram == 0)
|
||
{
|
||
lower_size_ram = lower->region->current - lower->region->origin;
|
||
upper_size_ram = upper->region->current - upper->region->origin;
|
||
}
|
||
lower_size = &lower_size_ram;
|
||
upper_size = &upper_size_ram;
|
||
}
|
||
|
||
/* Move sections in the upper region that would fit in the lower
|
||
region to the lower region. */
|
||
if (*lower_size + s->size < lower->region->length)
|
||
{
|
||
if (change_output_section (&(upper->children.head), s, lower))
|
||
{
|
||
*upper_size -= s->size;
|
||
*lower_size += s->size;
|
||
}
|
||
}
|
||
end:
|
||
free (either_name);
|
||
}
|
||
|
||
static void
|
||
eval_lower_either_sections (bfd *abfd ATTRIBUTE_UNUSED,
|
||
asection *s, void *data)
|
||
{
|
||
const char * base_sec_name;
|
||
const char * curr_name;
|
||
char * either_name;
|
||
int curr_region;
|
||
lang_output_section_statement_type * output_sec;
|
||
lang_output_section_statement_type * lower;
|
||
lang_output_section_statement_type * upper;
|
||
|
||
static bfd_size_type *lower_size = 0;
|
||
static bfd_size_type lower_size_rom = 0;
|
||
static bfd_size_type lower_size_ram = 0;
|
||
|
||
if ((s->flags & SEC_ALLOC) == 0)
|
||
return;
|
||
if (bfd_link_relocatable (&link_info))
|
||
return;
|
||
|
||
base_sec_name = (const char *) data;
|
||
curr_name = bfd_section_name (s);
|
||
|
||
/* Only concerned with .either input sections in the lower or "default"
|
||
output section i.e. not in the upper output section. */
|
||
either_name = concat (".either", base_sec_name, NULL);
|
||
if (strncmp (curr_name, either_name, strlen (either_name)) != 0
|
||
|| strncmp (s->output_section->name, ".upper", 6) == 0)
|
||
return;
|
||
|
||
if (strcmp (base_sec_name, ".text") == 0
|
||
|| strcmp (base_sec_name, ".rodata") == 0)
|
||
curr_region = ROM;
|
||
else
|
||
curr_region = RAM;
|
||
|
||
output_sec = lang_output_section_find (s->output_section->name);
|
||
|
||
/* If the output_section doesn't exist, this has already been reported in
|
||
place_orphan, so don't need to warn again. */
|
||
if (output_sec == NULL || output_sec->region == NULL)
|
||
goto end;
|
||
|
||
/* lower and output_sec might be the same, but in some cases an .either
|
||
section can end up in base_sec_name if it hasn't been placed by
|
||
place_orphan. */
|
||
lower = lang_output_section_find (concat (".lower", base_sec_name, NULL));
|
||
upper = lang_output_section_find (concat (".upper", base_sec_name, NULL));
|
||
if (upper == NULL)
|
||
goto end;
|
||
|
||
if (curr_region == ROM)
|
||
{
|
||
if (lower_size_rom == 0)
|
||
{
|
||
/* Get the size of other items in the lower region that aren't the
|
||
sections to be moved around. */
|
||
lower_size_rom
|
||
= (output_sec->region->current - output_sec->region->origin)
|
||
- scan_children (output_sec->children.head);
|
||
if (output_sec != lower && lower != NULL)
|
||
lower_size_rom -= scan_children (lower->children.head);
|
||
}
|
||
lower_size = &lower_size_rom;
|
||
}
|
||
else if (curr_region == RAM)
|
||
{
|
||
if (lower_size_ram == 0)
|
||
{
|
||
lower_size_ram
|
||
= (output_sec->region->current - output_sec->region->origin)
|
||
- scan_children (output_sec->children.head);
|
||
if (output_sec != lower && lower != NULL)
|
||
lower_size_ram -= scan_children (lower->children.head);
|
||
}
|
||
lower_size = &lower_size_ram;
|
||
}
|
||
/* Move sections that cause the lower region to overflow to the upper region. */
|
||
if (*lower_size + s->size > output_sec->region->length)
|
||
change_output_section (&(output_sec->children.head), s, upper);
|
||
else
|
||
*lower_size += s->size;
|
||
end:
|
||
free (either_name);
|
||
}
|
||
|
||
/* This function is similar to lang_relax_sections, but without the size
|
||
evaluation code that is always executed after relaxation. */
|
||
static void
|
||
intermediate_relax_sections (void)
|
||
{
|
||
int i = link_info.relax_pass;
|
||
|
||
/* The backend can use it to determine the current pass. */
|
||
link_info.relax_pass = 0;
|
||
|
||
while (i--)
|
||
{
|
||
bfd_boolean relax_again;
|
||
|
||
link_info.relax_trip = -1;
|
||
do
|
||
{
|
||
link_info.relax_trip++;
|
||
|
||
lang_do_assignments (lang_assigning_phase_enum);
|
||
|
||
lang_reset_memory_regions ();
|
||
|
||
relax_again = FALSE;
|
||
lang_size_sections (&relax_again, FALSE);
|
||
}
|
||
while (relax_again);
|
||
|
||
link_info.relax_pass++;
|
||
}
|
||
}
|
||
|
||
static void
|
||
msp430_elf_after_allocation (void)
|
||
{
|
||
int relax_count = 0;
|
||
unsigned int i;
|
||
/* Go over each section twice, once to place either sections that don't fit
|
||
in lower into upper, and then again to move any sections in upper that
|
||
fit in lower into lower. */
|
||
for (i = 0; i < 8; i++)
|
||
{
|
||
int placement_stage = (i < 4) ? LOWER_TO_UPPER : UPPER_TO_LOWER;
|
||
const char * base_sec_name;
|
||
lang_output_section_statement_type * upper;
|
||
|
||
switch (i % 4)
|
||
{
|
||
default:
|
||
case 0:
|
||
base_sec_name = ".text";
|
||
break;
|
||
case 1:
|
||
base_sec_name = ".data";
|
||
break;
|
||
case 2:
|
||
base_sec_name = ".bss";
|
||
break;
|
||
case 3:
|
||
base_sec_name = ".rodata";
|
||
break;
|
||
}
|
||
upper = lang_output_section_find (concat (".upper", base_sec_name, NULL));
|
||
if (upper != NULL)
|
||
{
|
||
/* Can't just use one iteration over the all the sections to make
|
||
both lower->upper and upper->lower transformations because the
|
||
iterator encounters upper sections before all lower sections have
|
||
been examined. */
|
||
bfd *abfd;
|
||
|
||
if (placement_stage == LOWER_TO_UPPER)
|
||
{
|
||
/* Perform relaxation and get the final size of sections
|
||
before trying to fit .either sections in the correct
|
||
ouput sections. */
|
||
if (relax_count == 0)
|
||
{
|
||
intermediate_relax_sections ();
|
||
relax_count++;
|
||
}
|
||
for (abfd = link_info.input_bfds; abfd != NULL;
|
||
abfd = abfd->link.next)
|
||
{
|
||
bfd_map_over_sections (abfd, eval_lower_either_sections,
|
||
(void *) base_sec_name);
|
||
}
|
||
}
|
||
else if (placement_stage == UPPER_TO_LOWER)
|
||
{
|
||
/* Relax again before moving upper->lower. */
|
||
if (relax_count == 1)
|
||
{
|
||
intermediate_relax_sections ();
|
||
relax_count++;
|
||
}
|
||
for (abfd = link_info.input_bfds; abfd != NULL;
|
||
abfd = abfd->link.next)
|
||
{
|
||
bfd_map_over_sections (abfd, eval_upper_either_sections,
|
||
(void *) base_sec_name);
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
gld${EMULATION_NAME}_after_allocation ();
|
||
}
|
||
|
||
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},
|
||
msp430_elf_after_open,
|
||
after_check_relocs_default,
|
||
msp430_elf_after_allocation,
|
||
${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},
|
||
gld${EMULATION_NAME}_add_options,
|
||
gld${EMULATION_NAME}_handle_option,
|
||
${LDEMUL_UNRECOGNIZED_FILE-NULL},
|
||
gld${EMULATION_NAME}_list_options,
|
||
${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:
|