Browse Source
* aout.sc: Don't define __DYNAMIC here. Add new sections used by shared library support code. * emultempl/sunos.em: New file. * emulparams/sun4.sh (TEMPLATE_NAME): Define as sunos. * Makefile.in (esun4.c): Depend upon sunos.em, not generic.em.gdb-4_18-branch
5 changed files with 637 additions and 1 deletions
@ -0,0 +1,564 @@ |
|||
# This shell script emits a C file. -*- C -*- |
|||
# It does some substitutions. |
|||
cat >e${EMULATION_NAME}.c <<EOF |
|||
/* This file is is generated by a shell script. DO NOT EDIT! */ |
|||
|
|||
/* SunOS emulation code for ${EMULATION_NAME} |
|||
Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc. |
|||
Written by Steve Chamberlain <sac@cygnus.com> |
|||
SunOS shared library support by Ian Lance Taylor <ian@cygnus.com> |
|||
|
|||
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., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|||
|
|||
#define TARGET_IS_${EMULATION_NAME} |
|||
|
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
|
|||
/* FIXME: On some hosts we will need to include a different file. |
|||
This is correct for SunOS, which is the only place this file will |
|||
typically be compiled. However, if somebody configures the linker |
|||
for all targets, they will run into trouble here. */ |
|||
#include <dirent.h> |
|||
|
|||
#include "bfd.h" |
|||
#include "sysdep.h" |
|||
#include "bfdlink.h" |
|||
|
|||
#include "ld.h" |
|||
#include "config.h" |
|||
#include "ldmain.h" |
|||
#include "ldemul.h" |
|||
#include "ldfile.h" |
|||
#include "ldmisc.h" |
|||
#include "ldexp.h" |
|||
#include "ldlang.h" |
|||
|
|||
static void gld${EMULATION_NAME}_before_parse PARAMS ((void)); |
|||
static void gld${EMULATION_NAME}_create_output_section_statements |
|||
PARAMS ((void)); |
|||
static void gld${EMULATION_NAME}_find_so |
|||
PARAMS ((lang_input_statement_type *)); |
|||
static void gld${EMULATION_NAME}_before_allocation PARAMS ((void)); |
|||
static void gld${EMULATION_NAME}_find_statement_assignment |
|||
PARAMS ((lang_statement_union_type *)); |
|||
static void gld${EMULATION_NAME}_find_exp_assignment PARAMS ((etree_type *)); |
|||
static void gld${EMULATION_NAME}_count_need |
|||
PARAMS ((lang_input_statement_type *)); |
|||
static void gld${EMULATION_NAME}_set_need |
|||
PARAMS ((lang_input_statement_type *)); |
|||
static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile)); |
|||
|
|||
static void |
|||
gld${EMULATION_NAME}_before_parse() |
|||
{ |
|||
ldfile_output_architecture = bfd_arch_${ARCH}; |
|||
config.dynamic_link = true; |
|||
} |
|||
|
|||
/* Despite the name, we use this routine to search for dynamic |
|||
libraries. On SunOS this requires a directory search. We need to |
|||
find the .so file with the highest version number. The user may |
|||
restrict the major version by saying, e.g., -lc.1. Also, if we |
|||
find a .so file, we need to look for a the same file after |
|||
replacing .so with .sa; if it exists, it will be an archive which |
|||
provide some initializations for data symbols, and we need to |
|||
search it after including the .so file. */ |
|||
|
|||
static void |
|||
gld${EMULATION_NAME}_create_output_section_statements () |
|||
{ |
|||
lang_for_each_input_file (gld${EMULATION_NAME}_find_so); |
|||
} |
|||
|
|||
/* Search the directory for a .so file for each library search. */ |
|||
|
|||
static void |
|||
gld${EMULATION_NAME}_find_so (inp) |
|||
lang_input_statement_type *inp; |
|||
{ |
|||
search_dirs_type *search; |
|||
const char *filename; |
|||
const char *dot; |
|||
int force_maj; |
|||
unsigned int len; |
|||
char *alc; |
|||
int max_maj, max_min; |
|||
char *found; |
|||
struct stat st; |
|||
|
|||
if (! inp->search_dirs_flag |
|||
|| ! inp->is_archive) |
|||
return; |
|||
|
|||
ASSERT (strncmp (inp->local_sym_name, "-l", 2) == 0); |
|||
|
|||
filename = inp->filename; |
|||
force_maj = -1; |
|||
dot = strchr (filename, '.'); |
|||
if (dot == NULL) |
|||
len = strlen (filename); |
|||
else |
|||
{ |
|||
len = dot - filename; |
|||
alc = (char *) alloca (len + 1); |
|||
strncpy (alc, filename, len); |
|||
alc[len] = '\0'; |
|||
filename = alc; |
|||
} |
|||
|
|||
found = NULL; |
|||
max_maj = max_min = 0; |
|||
for (search = search_head; search != NULL; search = search->next) |
|||
{ |
|||
DIR *dir; |
|||
struct dirent *entry; |
|||
|
|||
dir = opendir (search->name); |
|||
if (dir == NULL) |
|||
continue; |
|||
|
|||
while ((entry = readdir (dir)) != NULL) |
|||
{ |
|||
int found_maj, found_min; |
|||
|
|||
if (strncmp (entry->d_name, "lib", 3) != 0 |
|||
|| strncmp (entry->d_name + 3, inp->filename, len) != 0 |
|||
|| strncmp (entry->d_name + 3 + len, ".so", 3) != 0) |
|||
continue; |
|||
|
|||
/* We've found a .so file. Work out the major and minor |
|||
version numbers. */ |
|||
found_maj = 0; |
|||
found_min = 0; |
|||
sscanf (entry->d_name + 3 + len, ".so.%d.%d", |
|||
&found_maj, &found_min); |
|||
|
|||
if (force_maj != -1 && force_maj != found_maj) |
|||
continue; |
|||
|
|||
/* We've found a match for the name we are searching for. |
|||
See if this is the version we should use. If the major |
|||
and minor versions match, we use the last entry in |
|||
alphabetical order; I don't know if this is how SunOS |
|||
distinguishes libc.so.1.8 from libc.so.1.8.1, but it |
|||
ought to suffice. */ |
|||
if (found == NULL |
|||
|| (found_maj > max_maj) |
|||
|| (found_maj == max_maj |
|||
&& (found_min > max_min |
|||
|| (found_min == max_min |
|||
&& strcmp (entry->d_name, found) > 0)))) |
|||
{ |
|||
if (found != NULL) |
|||
free (found); |
|||
found = (char *) xmalloc (strlen (entry->d_name) + 1); |
|||
strcpy (found, entry->d_name); |
|||
max_maj = found_maj; |
|||
max_min = found_min; |
|||
} |
|||
} |
|||
|
|||
closedir (dir); |
|||
|
|||
if (found != NULL) |
|||
break; |
|||
} |
|||
|
|||
if (found == NULL) |
|||
{ |
|||
/* We did not find a matching .so file. This isn't an error, |
|||
since there might still be a matching .a file, which will be |
|||
found by the usual search. */ |
|||
return; |
|||
} |
|||
|
|||
/* Replace the filename with the one we have found. */ |
|||
alc = (char *) xmalloc (strlen (search->name) + strlen (found) + 2); |
|||
sprintf (alc, "%s/%s", search->name, found); |
|||
inp->filename = alc; |
|||
|
|||
/* Turn off the search_dirs_flag to prevent ldfile_open_file from |
|||
searching for this file again. */ |
|||
inp->search_dirs_flag = false; |
|||
|
|||
free (found); |
|||
|
|||
/* Now look for the same file name, but with .sa instead of .so. If |
|||
found, add it to the list of input files. */ |
|||
alc = (char *) alloca (strlen (inp->filename) + 1); |
|||
strcpy (alc, inp->filename); |
|||
strstr (alc, ".so.")[2] = 'a'; |
|||
if (stat (alc, &st) == 0) |
|||
{ |
|||
lang_input_statement_type *sa; |
|||
char *a; |
|||
|
|||
/* Add the .sa file to the statement list just after the .so |
|||
file. This is really a hack. */ |
|||
sa = ((lang_input_statement_type *) |
|||
xmalloc (sizeof (lang_input_statement_type))); |
|||
sa->header.next = inp->header.next; |
|||
sa->header.type = lang_input_statement_enum; |
|||
a = (char *) xmalloc (strlen (alc) + 1); |
|||
strcpy (a, alc); |
|||
sa->filename = a; |
|||
sa->local_sym_name = a; |
|||
sa->the_bfd = NULL; |
|||
sa->asymbols = NULL; |
|||
sa->symbol_count = 0; |
|||
sa->next = inp->next; |
|||
sa->next_real_file = inp->next_real_file; |
|||
sa->is_archive = false; |
|||
sa->search_dirs_flag = false; |
|||
sa->just_syms_flag = false; |
|||
sa->loaded = false; |
|||
|
|||
inp->header.next = (lang_statement_union_type *) sa; |
|||
inp->next = (lang_statement_union_type *) sa; |
|||
inp->next_real_file = (lang_statement_union_type *) sa; |
|||
} |
|||
} |
|||
|
|||
/* We need to use static variables to pass information around the call |
|||
to lang_for_each_input_file. Ick. */ |
|||
|
|||
static bfd_size_type need_size; |
|||
static bfd_size_type need_entries; |
|||
static bfd_byte *need_contents; |
|||
static bfd_byte *need_pinfo; |
|||
static bfd_byte *need_pnames; |
|||
|
|||
/* The size of one entry in the .need section, not including the file |
|||
name. */ |
|||
|
|||
#define NEED_ENTRY_SIZE (16) |
|||
|
|||
/* This is called after the sections have been attached to output |
|||
sections, but before any sizes or addresses have been set. */ |
|||
|
|||
static void |
|||
gld${EMULATION_NAME}_before_allocation () |
|||
{ |
|||
struct bfd_link_hash_entry *h = NULL; |
|||
asection *sneed; |
|||
asection *srules; |
|||
asection *sdyn; |
|||
|
|||
/* We need to create a __DYNAMIC symbol. We don't do this in the |
|||
linker script because we want to set the value to the start of |
|||
the dynamic section if there is one, or to zero if there isn't |
|||
one. We need to create the symbol before calling |
|||
size_dynamic_sections, although we can't set the value until |
|||
afterward. */ |
|||
if (! link_info.relocateable) |
|||
{ |
|||
h = bfd_link_hash_lookup (link_info.hash, "__DYNAMIC", true, false, |
|||
false); |
|||
if (h == NULL) |
|||
einfo ("%P%F: bfd_link_hash_lookup: %E\n"); |
|||
if (! bfd_sunos_record_link_assignment (output_bfd, &link_info, |
|||
"__DYNAMIC")) |
|||
einfo ("%P%F: failed to record assignment to __DYNAMIC: %E\n"); |
|||
} |
|||
|
|||
/* If we are going to make any variable assignments, we need to let |
|||
the backend linker know about them in case the variables are |
|||
referred to by dynamic objects. */ |
|||
lang_for_each_statement (gld${EMULATION_NAME}_find_statement_assignment); |
|||
|
|||
/* Let the backend linker work out the sizes of any sections |
|||
required by dynamic linking. */ |
|||
if (! bfd_sunos_size_dynamic_sections (output_bfd, &link_info, &sdyn, |
|||
&sneed, &srules)) |
|||
einfo ("%P%F: failed to set dynamic section sizes: %E\n"); |
|||
|
|||
if (sneed != NULL) |
|||
{ |
|||
/* Set up the .need section. See the description of the ld_need |
|||
field in include/sun4/aout.h. */ |
|||
|
|||
need_entries = 0; |
|||
need_size = 0; |
|||
|
|||
lang_for_each_input_file (gld${EMULATION_NAME}_count_need); |
|||
|
|||
/* We should only have a .need section if we have at least one |
|||
dynamic object. */ |
|||
ASSERT (need_entries != 0); |
|||
|
|||
sneed->_raw_size = need_size; |
|||
sneed->contents = (bfd_byte *) xmalloc (need_size); |
|||
|
|||
need_contents = sneed->contents; |
|||
need_pinfo = sneed->contents; |
|||
need_pnames = sneed->contents + need_entries * 16; |
|||
|
|||
lang_for_each_input_file (gld${EMULATION_NAME}_set_need); |
|||
|
|||
ASSERT (need_pnames - sneed->contents == need_size); |
|||
} |
|||
|
|||
if (srules != NULL) |
|||
{ |
|||
unsigned int size; |
|||
search_dirs_type *search; |
|||
|
|||
/* Set up the .rules section. This is just a PATH like string |
|||
of the -L arguments given on the command line. */ |
|||
size = 0; |
|||
for (search = search_head; search != NULL; search = search->next) |
|||
if (search->cmdline) |
|||
size += strlen (search->name) + 1; |
|||
srules->_raw_size = size; |
|||
if (size > 0) |
|||
{ |
|||
char *p; |
|||
|
|||
srules->contents = (bfd_byte *) xmalloc (size); |
|||
p = (char *) srules->contents; |
|||
*p = '\0'; |
|||
for (search = search_head; search != NULL; search = search->next) |
|||
{ |
|||
if (search->cmdline) |
|||
{ |
|||
if (p != (char *) srules->contents) |
|||
*p++ = ':'; |
|||
strcpy (p, search->name); |
|||
p += strlen (p); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* We must assign a value to __DYNAMIC. It should be zero if we are |
|||
not doing a dynamic link, or the start of the .dynamic section if |
|||
we are doing one. */ |
|||
if (! link_info.relocateable) |
|||
{ |
|||
h->type = bfd_link_hash_defined; |
|||
h->u.def.value = 0; |
|||
if (sdyn != NULL) |
|||
h->u.def.section = sdyn; |
|||
else |
|||
h->u.def.section = &bfd_abs_section; |
|||
} |
|||
} |
|||
|
|||
/* This is called by the before_allocation routine via |
|||
lang_for_each_statement. It locates any assignment statements, and |
|||
tells the backend linker about them, in case they are assignments |
|||
to symbols which are referred to by dynamic objects. */ |
|||
|
|||
static void |
|||
gld${EMULATION_NAME}_find_statement_assignment (s) |
|||
lang_statement_union_type *s; |
|||
{ |
|||
if (s->header.type == lang_assignment_statement_enum) |
|||
gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp); |
|||
} |
|||
|
|||
/* Look through an expression for an assignment statement. */ |
|||
|
|||
static void |
|||
gld${EMULATION_NAME}_find_exp_assignment (exp) |
|||
etree_type *exp; |
|||
{ |
|||
switch (exp->type.node_class) |
|||
{ |
|||
case etree_assign: |
|||
if (strcmp (exp->assign.dst, ".") != 0) |
|||
{ |
|||
if (! bfd_sunos_record_link_assignment (output_bfd, &link_info, |
|||
exp->assign.dst)) |
|||
einfo ("%P%F: failed to record assignment to %s: %E\n", |
|||
exp->assign.dst); |
|||
} |
|||
gld${EMULATION_NAME}_find_exp_assignment (exp->assign.src); |
|||
break; |
|||
|
|||
case etree_binary: |
|||
gld${EMULATION_NAME}_find_exp_assignment (exp->binary.lhs); |
|||
gld${EMULATION_NAME}_find_exp_assignment (exp->binary.rhs); |
|||
break; |
|||
|
|||
case etree_trinary: |
|||
gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs); |
|||
gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs); |
|||
gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.rhs); |
|||
break; |
|||
|
|||
case etree_unary: |
|||
gld${EMULATION_NAME}_find_exp_assignment (exp->unary.child); |
|||
break; |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
|
|||
/* Work out the size of the .need section, and the number of entries. |
|||
The backend will set the ld_need field of the dynamic linking |
|||
information to point to the .need section. See include/aout/sun4.h |
|||
for more information. */ |
|||
|
|||
static void |
|||
gld${EMULATION_NAME}_count_need (inp) |
|||
lang_input_statement_type *inp; |
|||
{ |
|||
if (inp->the_bfd != NULL |
|||
&& (inp->the_bfd->flags & DYNAMIC) != 0) |
|||
{ |
|||
++need_entries; |
|||
need_size += NEED_ENTRY_SIZE; |
|||
if (! inp->is_archive) |
|||
need_size += strlen (inp->filename) + 1; |
|||
else |
|||
{ |
|||
ASSERT (inp->local_sym_name[0] == '-' |
|||
&& inp->local_sym_name[1] == 'l'); |
|||
need_size += strlen (inp->local_sym_name + 2) + 1; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* Fill in the contents of the .need section. */ |
|||
|
|||
static void |
|||
gld${EMULATION_NAME}_set_need (inp) |
|||
lang_input_statement_type *inp; |
|||
{ |
|||
if (inp->the_bfd != NULL |
|||
&& (inp->the_bfd->flags & DYNAMIC) != 0) |
|||
{ |
|||
bfd_size_type c; |
|||
|
|||
/* To really fill in the .need section contents, we need to know |
|||
the final file position of the section, but we don't. |
|||
Instead, we use offsets, and rely on the BFD backend to |
|||
finish the section up correctly. FIXME: Talk about lack of |
|||
referential locality. */ |
|||
bfd_put_32 (output_bfd, need_pnames - need_contents, need_pinfo); |
|||
if (! inp->is_archive) |
|||
{ |
|||
bfd_put_32 (output_bfd, (bfd_vma) 0, need_pinfo + 4); |
|||
bfd_put_16 (output_bfd, (bfd_vma) 0, need_pinfo + 8); |
|||
bfd_put_16 (output_bfd, (bfd_vma) 0, need_pinfo + 10); |
|||
strcpy (need_pnames, inp->filename); |
|||
} |
|||
else |
|||
{ |
|||
char *verstr; |
|||
int maj, min; |
|||
|
|||
bfd_put_32 (output_bfd, (bfd_vma) 0x80000000, need_pinfo + 4); |
|||
maj = 0; |
|||
min = 0; |
|||
verstr = strstr (inp->filename, ".so."); |
|||
if (verstr != NULL) |
|||
sscanf (verstr, ".so.%d.%d", &maj, &min); |
|||
bfd_put_16 (output_bfd, (bfd_vma) maj, need_pinfo + 8); |
|||
bfd_put_16 (output_bfd, (bfd_vma) min, need_pinfo + 10); |
|||
strcpy (need_pnames, inp->local_sym_name + 2); |
|||
} |
|||
|
|||
c = (need_pinfo - need_contents) / NEED_ENTRY_SIZE; |
|||
if (c + 1 >= need_entries) |
|||
bfd_put_32 (output_bfd, (bfd_vma) 0, need_pinfo + 12); |
|||
else |
|||
bfd_put_32 (output_bfd, (bfd_vma) (c + 1) * NEED_ENTRY_SIZE, |
|||
need_pinfo + 12); |
|||
|
|||
need_pinfo += NEED_ENTRY_SIZE; |
|||
need_pnames += strlen (need_pnames) + 1; |
|||
} |
|||
} |
|||
|
|||
static char * |
|||
gld${EMULATION_NAME}_get_script(isfile) |
|||
int *isfile; |
|||
EOF |
|||
|
|||
if test -n "$COMPILE_IN" |
|||
then |
|||
# Scripts compiled in. |
|||
|
|||
# sed commands to quote an ld script as a C string. |
|||
sc='s/["\\]/\\&/g |
|||
s/$/\\n\\/ |
|||
1s/^/"/ |
|||
$s/$/n"/ |
|||
' |
|||
|
|||
cat >>e${EMULATION_NAME}.c <<EOF |
|||
{ |
|||
*isfile = 0; |
|||
|
|||
if (link_info.relocateable == true && config.build_constructors == true) |
|||
return `sed "$sc" ldscripts/${EMULATION_NAME}.xu`; |
|||
else if (link_info.relocateable == true) |
|||
return `sed "$sc" ldscripts/${EMULATION_NAME}.xr`; |
|||
else if (!config.text_read_only) |
|||
return `sed "$sc" ldscripts/${EMULATION_NAME}.xbn`; |
|||
else if (!config.magic_demand_paged) |
|||
return `sed "$sc" ldscripts/${EMULATION_NAME}.xn`; |
|||
else |
|||
return `sed "$sc" ldscripts/${EMULATION_NAME}.x`; |
|||
} |
|||
EOF |
|||
|
|||
else |
|||
# Scripts read from the filesystem. |
|||
|
|||
cat >>e${EMULATION_NAME}.c <<EOF |
|||
{ |
|||
*isfile = 1; |
|||
|
|||
if (link_info.relocateable == true && config.build_constructors == true) |
|||
return "ldscripts/${EMULATION_NAME}.xu"; |
|||
else if (link_info.relocateable == true) |
|||
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 |
|||
|
|||
cat >>e${EMULATION_NAME}.c <<EOF |
|||
|
|||
struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = |
|||
{ |
|||
gld${EMULATION_NAME}_before_parse, |
|||
syslib_default, |
|||
hll_default, |
|||
after_parse_default, |
|||
after_allocation_default, |
|||
set_output_arch_default, |
|||
ldemul_default_target, |
|||
gld${EMULATION_NAME}_before_allocation, |
|||
gld${EMULATION_NAME}_get_script, |
|||
"${EMULATION_NAME}", |
|||
"${OUTPUT_FORMAT}", |
|||
0, /* finish */ |
|||
gld${EMULATION_NAME}_create_output_section_statements |
|||
}; |
|||
EOF |
|||
@ -0,0 +1,44 @@ |
|||
cat <<EOF |
|||
OUTPUT_FORMAT("${OUTPUT_FORMAT}") |
|||
OUTPUT_ARCH(${ARCH}) |
|||
|
|||
${RELOCATING+${LIB_SEARCH_DIRS}} |
|||
${STACKZERO+${RELOCATING+${STACKZERO}}} |
|||
${SHLIB_PATH+${RELOCATING+${SHLIB_PATH}}} |
|||
SECTIONS |
|||
{ |
|||
.text ${RELOCATING+${TEXT_START_ADDR}}: |
|||
{ |
|||
CREATE_OBJECT_SYMBOLS |
|||
*(.text) |
|||
/* The next six sections are for SunOS dynamic linking. The order |
|||
is important. */ |
|||
*(.dynrel) |
|||
*(.hash) |
|||
*(.dynsym) |
|||
*(.dynstr) |
|||
*(.rules) |
|||
*(.need) |
|||
${PAD_TEXT+${RELOCATING+. = ${DATA_ALIGNMENT};}} |
|||
${RELOCATING+_etext = ${DATA_ALIGNMENT};} |
|||
} |
|||
.data ${RELOCATING+${DATA_ALIGNMENT}} : |
|||
{ |
|||
/* The first three sections are for SunOS dynamic linking. */ |
|||
*(.dynamic) |
|||
*(.got) |
|||
*(.plt) |
|||
*(.data) |
|||
${CONSTRUCTING+CONSTRUCTORS} |
|||
${RELOCATING+_edata = .;} |
|||
} |
|||
.bss ${RELOCATING+SIZEOF(.data) + ADDR(.data)} : |
|||
{ |
|||
${RELOCATING+ __bss_start = .}; |
|||
*(.bss) |
|||
*(COMMON) |
|||
${RELOCATING+_end = ALIGN(4) }; |
|||
${RELOCATING+__end = ALIGN(4) }; |
|||
} |
|||
} |
|||
EOF |
|||
Loading…
Reference in new issue