|
Message
From: Scott Furman <sfurman@r...>
Date: Wed, 12 Nov 2003 23:23:31 -0800
Subject: Re: [openrisc] gdb stub instead of JTAG?
Title:
Scott Furman wrote:
mid3FB31CEC.1090500@r...">
Attached are my linker fixes.
Oops ! Forgot to attach newly added file ld/emultempl/or32elf.em
You'll need that along with the patch I sent in my previous message.
-Scott
# This shell script emits a C file. -*- C -*-
# Copyright 2000, 2001 Free Software Foundation, Inc.
# Written by Michael Sokolov <msokolov@i...>, based on armelf.em
#
# This file is part of GLD, the Gnu Linker.
#
# 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# This file is sourced from elf32.em, and defines some extra routines for or32
# embedded systems using ELF and for some other systems using or32 ELF. While
# it is sourced from elf32.em for all or32 ELF configurations, here we include
# only the features we want depending on the configuration.
cat >>e${EMULATION_NAME}.c <<EOF
#include "safe-ctype.h"
#include "ldgram.h"
static lang_output_section_statement_type *output_rel_find
PARAMS ((void));
static asection *output_prev_sec_find
PARAMS ((lang_output_section_statement_type *));
static boolean gld${EMULATION_NAME}_place_orphan
PARAMS ((lang_input_statement_type *, asection *));
/* A variant of lang_output_section_find. Used by place_orphan. */
static lang_output_section_statement_type *
output_rel_find ()
{
lang_statement_union_type *u;
lang_output_section_statement_type *lookup;
for (u = lang_output_section_statement.head;
u != (lang_statement_union_type *) NULL;
u = lookup->next)
{
lookup = &u->output_section_statement;
if (strncmp (".rel", lookup->name, 4) == 0
&& lookup->bfd_section != NULL
&& (lookup->bfd_section->flags & SEC_ALLOC) != 0)
{
return lookup;
}
}
return (lang_output_section_statement_type *) NULL;
}
/* Find the last output section before given output statement.
Used by place_orphan. */
static asection *
output_prev_sec_find (os)
lang_output_section_statement_type *os;
{
asection *s = (asection *) NULL;
lang_statement_union_type *u;
lang_output_section_statement_type *lookup;
for (u = lang_output_section_statement.head;
u != (lang_statement_union_type *) NULL;
u = lookup->next)
{
lookup = &u->output_section_statement;
if (lookup == os)
return s;
if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL)
s = lookup->bfd_section;
}
return NULL;
}
/* Place an orphan section. We use this to put random SHF_ALLOC
sections in the right segment. */
struct orphan_save {
lang_output_section_statement_type *os;
asection **section;
lang_statement_union_type **stmt;
};
static boolean
gld${EMULATION_NAME}_place_orphan (file, s)
lang_input_statement_type *file;
asection *s;
{
static struct orphan_save hold_text;
static struct orphan_save hold_rodata;
static struct orphan_save hold_data;
static struct orphan_save hold_bss;
static struct orphan_save hold_rel;
static struct orphan_save hold_interp;
static struct orphan_save hold_sdata;
static int count = 1;
struct orphan_save *place;
lang_statement_list_type *old;
lang_statement_list_type add;
etree_type *address;
const char *secname;
const char *outsecname;
const char *ps = NULL;
lang_output_section_statement_type *os;
secname = bfd_get_section_name (s->owner, s);
if (! config.unique_orphan_sections && ! unique_section_p (secname))
{
/* Look through the script to see where to place this section. */
os = lang_output_section_find (secname);
if (os != NULL
&& (os->bfd_section == NULL
|| ((s->flags ^ os->bfd_section->flags)
& (SEC_LOAD | SEC_ALLOC)) == 0))
{
/* We already have an output section statement with this
name, and its bfd section, if any, has compatible flags. */
lang_add_section (&os->children, s, os, file);
return true;
}
}
if (hold_text.os == NULL)
hold_text.os = lang_output_section_find (".text");
/* If this is a final link, then always put .gnu.warning.SYMBOL
sections into the .text section to get them out of the way. */
if (! link_info.shared
&& ! link_info.relocateable
&& strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0
&& hold_text.os != NULL)
{
lang_add_section (&hold_text.os->children, s, hold_text.os, file);
return true;
}
/* Decide which segment the section should go in based on the
section name and section flags. We put loadable .note sections
right after the .interp section, so that the PT_NOTE segment is
stored right after the program headers where the OS can read it
in the first page. */
#define HAVE_SECTION(hold, name) \
(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL)
if (s->flags & SEC_EXCLUDE)
{
if (s->output_section == NULL)
s->output_section = bfd_abs_section_ptr;
return true;
}
place = NULL;
if ((s->flags & SEC_ALLOC) == 0)
;
else if ((s->flags & SEC_LOAD) != 0
&& strncmp (secname, ".note", 5) == 0
&& HAVE_SECTION (hold_interp, ".interp"))
place = &hold_interp;
else if ((s->flags & SEC_HAS_CONTENTS) == 0
&& HAVE_SECTION (hold_bss, ".bss"))
place = &hold_bss;
else if ((s->flags & SEC_SMALL_DATA) != 0
&& HAVE_SECTION (hold_sdata, ".sdata"))
place = &hold_sdata;
else if ((s->flags & SEC_READONLY) == 0
&& HAVE_SECTION (hold_data, ".data"))
place = &hold_data;
else if (strncmp (secname, ".rel", 4) == 0
&& (hold_rel.os != NULL
|| (hold_rel.os = output_rel_find ()) != NULL))
{
if (! link_info.relocateable && link_info.combreloc)
{
if (strncmp (secname, ".rela", 5) == 0)
os = lang_output_section_find (".rela.dyn");
else
os = lang_output_section_find (".rel.dyn");
if (os != NULL
&& os->bfd_section != NULL
&& ((s->flags ^ os->bfd_section->flags)
& (SEC_LOAD | SEC_ALLOC)) == 0)
{
lang_add_section (&os->children, s, os, file);
return true;
}
}
place = &hold_rel;
}
else if ((s->flags & (SEC_CODE | SEC_READONLY)) == SEC_READONLY
&& HAVE_SECTION (hold_rodata, ".rodata"))
place = &hold_rodata;
else if ((s->flags & (SEC_CODE | SEC_READONLY)) == (SEC_CODE | SEC_READONLY)
&& hold_text.os != NULL)
place = &hold_text;
#undef HAVE_SECTION
/* Choose a unique name for the section. This will be needed if the
same section name appears in the input file with different
loadable or allocatable characteristics. */
outsecname = secname;
if (bfd_get_section_by_name (output_bfd, outsecname) != NULL)
{
outsecname = bfd_get_unique_section_name (output_bfd,
outsecname,
&count);
if (outsecname == NULL)
einfo ("%F%P: place_orphan failed: %E\n");
}
/* Start building a list of statements for this section.
First save the current statement pointer. */
old = stat_ptr;
/* If we have found an appropriate place for the output section
statements for this orphan, add them to our own private list,
inserting them later into the global statement list. */
if (place != NULL)
{
stat_ptr = &add;
lang_list_init (stat_ptr);
}
if (config.build_constructors)
{
/* If the name of the section is representable in C, then create
symbols to mark the start and the end of the section. */
for (ps = outsecname; *ps != '\0'; ps++)
if (! ISALNUM (*ps) && *ps != '_')
break;
if (*ps == '\0')
{
char *symname;
etree_type *e_align;
symname = (char *) xmalloc (ps - outsecname + sizeof "__start_");
sprintf (symname, "__start_%s", outsecname);
e_align = exp_unop (ALIGN_K,
exp_intop ((bfd_vma) 1 << s->alignment_power));
lang_add_assignment (exp_assop ('=', symname, e_align));
}
}
if (link_info.relocateable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
address = exp_intop ((bfd_vma) 0);
else
address = NULL;
os = lang_enter_output_section_statement (outsecname, address, 0,
(bfd_vma) 0,
(etree_type *) NULL,
(etree_type *) NULL,
(etree_type *) NULL);
lang_add_section (&os->children, s, os, file);
lang_leave_output_section_statement
((bfd_vma) 0, "*default*",
(struct lang_output_section_phdr_list *) NULL, "*default*");
if (config.build_constructors && *ps == '\0')
{
char *symname;
/* lang_leave_ouput_section_statement resets stat_ptr. Put
stat_ptr back where we want it. */
if (place != NULL)
stat_ptr = &add;
symname = (char *) xmalloc (ps - outsecname + sizeof "__stop_");
sprintf (symname, "__stop_%s", outsecname);
lang_add_assignment (exp_assop ('=', symname,
exp_nameop (NAME, ".")));
}
/* Restore the global list pointer. */
stat_ptr = old;
if (place != NULL)
{
asection *snew, **pps;
snew = os->bfd_section;
/* Shuffle the bfd section list to make the output file look
neater. This is really only cosmetic. */
if (place->section == NULL)
{
asection *bfd_section = place->os->bfd_section;
/* If the output statement hasn't been used to place
any input sections (and thus doesn't have an output
bfd_section), look for the closest prior output statement
having an output section. */
if (bfd_section == NULL)
bfd_section = output_prev_sec_find (place->os);
if (bfd_section != NULL && bfd_section != snew)
place->section = &bfd_section->next;
}
if (place->section != NULL)
{
/* Unlink the section. */
for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
;
bfd_section_list_remove (output_bfd, pps);
/* Now tack it on to the "place->os" section list. */
bfd_section_list_insert (output_bfd, place->section, snew);
}
/* Save the end of this list. Further ophans of this type will
follow the one we've just added. */
place->section = &snew->next;
/* The following is non-cosmetic. We try to put the output
statements in some sort of reasonable order here, because
they determine the final load addresses of the orphan
sections. In addition, placing output statements in the
wrong order may require extra segments. For instance,
given a typical situation of all read-only sections placed
in one segment and following that a segment containing all
the read-write sections, we wouldn't want to place an orphan
read/write section before or amongst the read-only ones. */
if (add.head != NULL)
{
if (place->stmt == NULL)
{
/* Put the new statement list right at the head. */
*add.tail = place->os->header.next;
place->os->header.next = add.head;
}
else
{
/* Put it after the last orphan statement we added. */
*add.tail = *place->stmt;
*place->stmt = add.head;
}
/* Fix the global list pointer if we happened to tack our
new list at the tail. */
if (*old->tail == add.head)
old->tail = add.tail;
/* Save the end of this list. */
place->stmt = add.tail;
}
}
return true;
}
EOF
LDEMUL_PLACE_ORPHAN=gld${EMULATION_NAME}_place_orphan
|
 |