From ba916c8af2642aebace1778a707e90a6a4f9095f Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Tue, 26 Oct 2004 18:41:52 +0000 Subject: * Makefile.in (earmsymbian.c): Depend on armbpabi.sc, not elf.sc. * ldexp.h (segment_type): New type. (segments): New variable. * ldexp.c (segments): New variable. (exp_print_token): Handle SEGMENT_START. (fold_binary): Likewise. * ldgram.y (SEGMENT_START): Declare it as a token. (exp): Handle SEGMENT_START. * ldlang.h (lang_address_statement_type): Add segment field. (lang_section_start): Change prototype. * ldlang.c (map_input_to_output_sections): Do not process section assignments if a corresponding SEGMENT_START has already been seen. (lang_section_start): Add segment parameter. * ldlex.l (SEGMENT_START): Add it. * lexsup.c (seg_segment_start): New function. (parse_args): Use it for -Tbss, -Tdata, and -Ttext. * ld.texinfo (SEGMENT_START): Document it. * emulparams/armsymbian.sh (EMBEDDED): Set it. * scripttempl/armbpabi.sc: Use SEGMENT_START to control segment base addresses. Do not map relocations. * NEWS: Mention SEGMENT_START. --- ld/ChangeLog | 25 ++++++ ld/Makefile.in | 2 +- ld/NEWS | 3 + ld/emulparams/armsymbian.sh | 2 + ld/ld.texinfo | 10 +++ ld/ldexp.c | 27 +++++- ld/ldexp.h | 16 ++++ ld/ldgram.y | 10 +++ ld/ldlang.c | 35 +++++--- ld/ldlang.h | 3 +- ld/ldlex.l | 1 + ld/lexsup.c | 45 +++++++++- ld/scripttempl/armbpabi.sc | 205 ++++++++++++++++---------------------------- ld/scripttempl/elf.sc | 3 + 14 files changed, 236 insertions(+), 151 deletions(-) (limited to 'ld') diff --git a/ld/ChangeLog b/ld/ChangeLog index 8641359..757860d 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,28 @@ +2004-10-25 Mark Mitchell + + * Makefile.in (earmsymbian.c): Depend on armbpabi.sc, not elf.sc. + * ldexp.h (segment_type): New type. + (segments): New variable. + * ldexp.c (segments): New variable. + (exp_print_token): Handle SEGMENT_START. + (fold_binary): Likewise. + * ldgram.y (SEGMENT_START): Declare it as a token. + (exp): Handle SEGMENT_START. + * ldlang.h (lang_address_statement_type): Add segment field. + (lang_section_start): Change prototype. + * ldlang.c (map_input_to_output_sections): Do not process section + assignments if a corresponding SEGMENT_START has already been + seen. + (lang_section_start): Add segment parameter. + * ldlex.l (SEGMENT_START): Add it. + * lexsup.c (seg_segment_start): New function. + (parse_args): Use it for -Tbss, -Tdata, and -Ttext. + * ld.texinfo (SEGMENT_START): Document it. + * emulparams/armsymbian.sh (EMBEDDED): Set it. + * scripttempl/armbpabi.sc: Use SEGMENT_START to control segment + base addresses. Do not map relocations. + * NEWS: Mention SEGMENT_START. + 2004-10-26 Paul Brook * ld.texinfo: Document --default-symver. diff --git a/ld/Makefile.in b/ld/Makefile.in index 10a3c9f..9997034 100644 --- a/ld/Makefile.in +++ b/ld/Makefile.in @@ -1276,7 +1276,7 @@ earmpe.c: $(srcdir)/emulparams/armpe.sh \ ${GENSCRIPTS} armpe "$(tdir_armpe)" earmsymbian.c: $(srcdir)/emulparams/armsymbian.sh \ $(srcdir)/emulparams/armelf.sh $(srcdir)/emultempl/elf32.em \ - $(srcdir)/emultempl/armelf.em $(srcdir)/scripttempl/elf.sc \ + $(srcdir)/emultempl/armelf.em $(srcdir)/scripttempl/armbpabi.sc \ ${GEN_DEPENDS} ${GENSCRIPTS} armsymbian "$(tdir_armelf)" eavr2.c: $(srcdir)/emulparams/avr2.sh \ diff --git a/ld/NEWS b/ld/NEWS index 403b823..03bd4f6 100644 --- a/ld/NEWS +++ b/ld/NEWS @@ -1,5 +1,8 @@ -*- text -*- +* Added SEGMENT_START to the linker script language to permit the user to + override the base address for a segment from the command-line. + * ELF: --warn-shared-textrel option to warn if adding a DT_TEXTREL to a shared object. diff --git a/ld/emulparams/armsymbian.sh b/ld/emulparams/armsymbian.sh index 6fd1d15..a5c3eb5 100644 --- a/ld/emulparams/armsymbian.sh +++ b/ld/emulparams/armsymbian.sh @@ -6,6 +6,8 @@ BIG_OUTPUT_FORMAT="elf32-bigarm-symbian" LITTLE_OUTPUT_FORMAT="$OUTPUT_FORMAT" TARGET1_IS_REL=1 TARGET2_TYPE=abs +# On BPABI systems, program headers should not be mapped. +EMBEDDED=yes # This value should match ELF_MAXPAGESIZE in BFD. Otherwise, elf.c # will not place read-write sections in a separate ELF segment from diff --git a/ld/ld.texinfo b/ld/ld.texinfo index 5944f44..597c705 100644 --- a/ld/ld.texinfo +++ b/ld/ld.texinfo @@ -4680,6 +4680,16 @@ This function is closely related to @code{ALIGN(@var{exp})}; unless you use the @code{MEMORY} command to define discontinuous memory for the output file, the two functions are equivalent. +@item SEGMENT_START(@var{segment}, @var{default}) +@kindex SEGMENT_START(@var{segment}, @var{default}) +Return the base address of the named @var{segment}. If an explicit +value has been given for this segment (with a command-line @samp{-T} +option) that value will be returned; otherwise the value will be +@var{default}. At present, the @samp{-T} command-line option can only +be used to set the base address for the ``text'', ``data'', and +``bss'' sections, but you use @code{SEGMENT_START} with any segment +name. + @item SIZEOF(@var{section}) @kindex SIZEOF(@var{section}) @cindex section size diff --git a/ld/ldexp.c b/ld/ldexp.c index 57968a2..103b615 100644 --- a/ld/ldexp.c +++ b/ld/ldexp.c @@ -48,6 +48,8 @@ static bfd_vma align_n struct exp_data_seg exp_data_seg; +segment_type *segments; + /* Print the string representation of the given token. Surround it with spaces if INFIX_P is TRUE. */ @@ -102,7 +104,8 @@ exp_print_token (token_code_type code, int infix_p) { REL, "relocatable" }, { DATA_SEGMENT_ALIGN, "DATA_SEGMENT_ALIGN" }, { DATA_SEGMENT_RELRO_END, "DATA_SEGMENT_RELRO_END" }, - { DATA_SEGMENT_END, "DATA_SEGMENT_END" } + { DATA_SEGMENT_END, "DATA_SEGMENT_END" }, + { SEGMENT_START, "SEGMENT_START" } }; unsigned int idx; @@ -305,7 +308,27 @@ fold_binary (etree_type *tree, result = exp_fold_tree (tree->binary.lhs, current_section, allocation_done, dot, dotp); - if (result.valid_p) + + /* The SEGMENT_START operator is special because its first + operand is a string, not the name of a symbol. */ + if (result.valid_p && tree->type.node_code == SEGMENT_START) + { + const char *segment_name; + segment_type *seg; + /* Check to see if the user has overridden the default + value. */ + segment_name = tree->binary.rhs->name.name; + for (seg = segments; seg; seg = seg->next) + if (strcmp (seg->name, segment_name) == 0) + { + seg->used = TRUE; + result.value = seg->value; + result.str = NULL; + result.section = NULL; + break; + } + } + else if (result.valid_p) { etree_value_type other; diff --git a/ld/ldexp.h b/ld/ldexp.h index a90f1ef..addf834 100644 --- a/ld/ldexp.h +++ b/ld/ldexp.h @@ -103,6 +103,22 @@ extern struct exp_data_seg { bfd_vma base, relro_end, end, pagesize; } exp_data_seg; +/* A maps from a segment name to a base address. */ +typedef struct segment_struct { + /* The next segment in the linked list. */ + struct segment_struct *next; + /* The name of the sgement. */ + const char *name; + /* The base address for the segment. */ + bfd_vma value; + /* True if a SEGMENT_START directive corresponding to this segment + has been seen. */ + bfd_boolean used; +} segment_type; + +/* The segments specified by the user on the command-line. */ +extern segment_type *segments; + typedef struct _fill_type fill_type; etree_type *exp_intop diff --git a/ld/ldgram.y b/ld/ldgram.y index bdfdcd5..13e4ca6 100644 --- a/ld/ldgram.y +++ b/ld/ldgram.y @@ -134,6 +134,7 @@ static int error_index; %token SIZEOF_HEADERS OUTPUT_FORMAT FORCE_COMMON_ALLOCATION OUTPUT_ARCH %token INHIBIT_COMMON_ALLOCATION %token SIZEOF_HEADERS +%token SEGMENT_START %token INCLUDE %token MEMORY DEFSYMEND %token NOLOAD DSECT COPY INFO OVERLAY @@ -843,6 +844,15 @@ exp : { $$ = exp_binop (DATA_SEGMENT_RELRO_END, $5, $3); } | DATA_SEGMENT_END '(' exp ')' { $$ = exp_unop(DATA_SEGMENT_END, $3); } + | SEGMENT_START '(' NAME ',' exp ')' + { /* The operands to the expression node are + placed in the opposite order from the way + in which they appear in the script as + that allows us to reuse more code in + fold_binary. */ + $$ = exp_binop (SEGMENT_START, + $5, + exp_nameop (NAME, $3)); } | BLOCK '(' exp ')' { $$ = exp_unop(ALIGN_K,$3); } | NAME diff --git a/ld/ldlang.c b/ld/ldlang.c index 3d1e5a41..c3a4934 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -2652,16 +2652,27 @@ map_input_to_output_sections FAIL (); break; case lang_address_statement_enum: - /* Mark the specified section with the supplied address. */ - { - lang_output_section_statement_type *aos - = (lang_output_section_statement_lookup - (s->address_statement.section_name)); - - if (aos->bfd_section == NULL) - init_os (aos); - aos->addr_tree = s->address_statement.address; - } + /* Mark the specified section with the supplied address. + + If this section was actually a segment marker, then the + directive is ignored if the linker script explicitly + processed the segment marker. Originally, the linker + treated segment directives (like -Ttext on the + command-line) as section directives. We honor the + section directive semantics for backwards compatibilty; + linker scripts that do not specifically check for + SEGMENT_START automatically get the old semantics. */ + if (!s->address_statement.segment + || !s->address_statement.segment->used) + { + lang_output_section_statement_type *aos + = (lang_output_section_statement_lookup + (s->address_statement.section_name)); + + if (aos->bfd_section == NULL) + init_os (aos); + aos->addr_tree = s->address_statement.address; + } break; } } @@ -4971,13 +4982,15 @@ lang_add_wild (struct wildcard_spec *filespec, } void -lang_section_start (const char *name, etree_type *address) +lang_section_start (const char *name, etree_type *address, + const segment_type *segment) { lang_address_statement_type *ad; ad = new_stat (lang_address_statement, stat_ptr); ad->section_name = name; ad->address = address; + ad->segment = segment; } /* Set the start symbol to NAME. CMDLINE is nonzero if this is called diff --git a/ld/ldlang.h b/ld/ldlang.h index d6b9a79..0862191 100644 --- a/ld/ldlang.h +++ b/ld/ldlang.h @@ -316,6 +316,7 @@ typedef struct lang_address_statement_struct lang_statement_header_type header; const char *section_name; union etree_union *address; + const segment_type *segment; } lang_address_statement_type; typedef struct @@ -461,7 +462,7 @@ extern void lang_final extern void lang_process (void); extern void lang_section_start - (const char *, union etree_union *); + (const char *, union etree_union *, const segment_type *); extern void lang_add_entry (const char *, bfd_boolean); extern void lang_add_target diff --git a/ld/ldlex.l b/ld/ldlex.l index e01332a..0ace6ec 100644 --- a/ld/ldlex.l +++ b/ld/ldlex.l @@ -261,6 +261,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)* "NEXT" { RTOKEN(NEXT);} "sizeof_headers" { RTOKEN(SIZEOF_HEADERS);} "SIZEOF_HEADERS" { RTOKEN(SIZEOF_HEADERS);} +"SEGMENT_START" { RTOKEN(SEGMENT_START);} "MAP" { RTOKEN(MAP);} "SIZEOF" { RTOKEN(SIZEOF);} "TARGET" { RTOKEN(TARGET_K);} diff --git a/ld/lexsup.c b/ld/lexsup.c index be7c0a9..28f28ff 100644 --- a/ld/lexsup.c +++ b/ld/lexsup.c @@ -55,6 +55,7 @@ static void set_default_dirlist (char *); static void set_section_start (char *, char *); +static void set_segment_start (const char *, char *); static void help (void); /* Non-zero if we are processing a --defsym from the command line. */ @@ -1138,13 +1139,13 @@ parse_args (unsigned argc, char **argv) ldemul_list_emulation_options (stdout); exit (0); case OPTION_TBSS: - set_section_start (".bss", optarg); + set_segment_start (".bss", optarg); break; case OPTION_TDATA: - set_section_start (".data", optarg); + set_segment_start (".data", optarg); break; case OPTION_TTEXT: - set_section_start (".text", optarg); + set_segment_start (".text", optarg); break; case OPTION_TRADITIONAL_FORMAT: link_info.traditional_format = TRUE; @@ -1380,8 +1381,44 @@ set_section_start (char *sect, char *valstr) bfd_vma val = bfd_scan_vma (valstr, &end, 16); if (*end) einfo (_("%P%F: invalid hex number `%s'\n"), valstr); - lang_section_start (sect, exp_intop (val)); + lang_section_start (sect, exp_intop (val), NULL); } + +static void +set_segment_start (const char *section, char *valstr) +{ + const char *name; + const char *end; + segment_type *seg; + + bfd_vma val = bfd_scan_vma (valstr, &end, 16); + if (*end) + einfo (_("%P%F: invalid hex number `%s'\n"), valstr); + /* If we already have an entry for this segment, update the existing + value. */ + name = section + 1; + for (seg = segments; seg; seg = seg->next) + if (strcmp (seg->name, name) == 0) + { + seg->value = val; + return; + } + /* There was no existing value so we must create a new segment + entry. */ + seg = stat_alloc (sizeof (*seg)); + seg->name = name; + seg->value = val; + seg->used = FALSE; + /* Add it to the linked list of segments. */ + seg->next = segments; + segments = seg; + /* Historically, -Ttext and friends set the base address of a + particular section. For backwards compatibility, we still do + that. If a SEGMENT_START directive is seen, the section address + assignment will be disabled. */ + lang_section_start (section, exp_intop (val), seg); +} + /* Print help messages for the options. */ diff --git a/ld/scripttempl/armbpabi.sc b/ld/scripttempl/armbpabi.sc index 6904ca9..33fae97 100644 --- a/ld/scripttempl/armbpabi.sc +++ b/ld/scripttempl/armbpabi.sc @@ -1,78 +1,7 @@ # This variant of elf.sc is used for ARM BPABI platforms, like Symbian # OS, where a separate postlinker will operated on the generated -# executable or shared object. - -# -# Unusual variables checked by this code: -# NOP - four byte opcode for no-op (defaults to 0) -# NO_SMALL_DATA - no .sbss/.sbss2/.sdata/.sdata2 sections if not -# empty. -# DATA_ADDR - if end-of-text-plus-one-page isn't right for data start -# INITIAL_READONLY_SECTIONS - at start of text segment -# OTHER_READONLY_SECTIONS - other than .text .init .rodata ... -# (e.g., .PARISC.milli) -# OTHER_TEXT_SECTIONS - these get put in .text when relocating -# OTHER_READWRITE_SECTIONS - other than .data .bss .ctors .sdata ... -# (e.g., .PARISC.global) -# OTHER_RELRO_SECTIONS - other than .data.rel.ro ... -# (e.g. PPC32 .fixup, .got[12]) -# OTHER_BSS_SECTIONS - other than .bss .sbss ... -# OTHER_SECTIONS - at the end -# EXECUTABLE_SYMBOLS - symbols that must be defined for an -# executable (e.g., _DYNAMIC_LINK) -# TEXT_START_SYMBOLS - symbols that appear at the start of the -# .text section. -# DATA_START_SYMBOLS - symbols that appear at the start of the -# .data section. -# OTHER_SDATA_SECTIONS - sections just after .sdata. -# OTHER_BSS_SYMBOLS - symbols that appear at the start of the -# .bss section besides __bss_start. -# DATA_PLT - .plt should be in data segment, not text segment. -# PLT_BEFORE_GOT - .plt just before .got when .plt is in data segement. -# BSS_PLT - .plt should be in bss segment -# TEXT_DYNAMIC - .dynamic in text segment, not data segment. -# EMBEDDED - whether this is for an embedded system. -# SHLIB_TEXT_START_ADDR - if set, add to SIZEOF_HEADERS to set -# start address of shared library. -# INPUT_FILES - INPUT command of files to always include -# WRITABLE_RODATA - if set, the .rodata section should be writable -# INIT_START, INIT_END - statements just before and just after -# combination of .init sections. -# FINI_START, FINI_END - statements just before and just after -# combination of .fini sections. -# STACK_ADDR - start of a .stack section. -# OTHER_END_SYMBOLS - symbols to place right at the end of the script. -# SEPARATE_GOTPLT - if set, .got.plt should be separate output section, -# so that .got can be in the RELRO area. It should be set to -# the number of bytes in the beginning of .got.plt which can be -# in the RELRO area as well. -# -# When adding sections, do note that the names of some sections are used -# when specifying the start address of the next. -# - -# Many sections come in three flavours. There is the 'real' section, -# like ".data". Then there are the per-procedure or per-variable -# sections, generated by -ffunction-sections and -fdata-sections in GCC, -# and useful for --gc-sections, which for a variable "foo" might be -# ".data.foo". Then there are the linkonce sections, for which the linker -# eliminates duplicates, which are named like ".gnu.linkonce.d.foo". -# The exact correspondences are: -# -# Section Linkonce section -# .text .gnu.linkonce.t.foo -# .rodata .gnu.linkonce.r.foo -# .data .gnu.linkonce.d.foo -# .bss .gnu.linkonce.b.foo -# .sdata .gnu.linkonce.s.foo -# .sbss .gnu.linkonce.sb.foo -# .sdata2 .gnu.linkonce.s2.foo -# .sbss2 .gnu.linkonce.sb2.foo -# .debug_info .gnu.linkonce.wi.foo -# .tdata .gnu.linkonce.td.foo -# .tbss .gnu.linkonce.tb.foo -# -# Each of these can also have corresponding .rel.* and .rela.* sections. +# executable or shared object. See elf.sc for configuration variables +# that apply; only BPABI-specific variables will be noted here. test -z "$ENTRY" && ENTRY=_start test -z "${BIG_OUTPUT_FORMAT}" && BIG_OUTPUT_FORMAT=${OUTPUT_FORMAT} @@ -175,11 +104,18 @@ STACK=" .stack ${RELOCATING-0}${RELOCATING+${STACK_ADDR}} : *(.stack) }" +TEXT_START_ADDR="SEGMENT_START(\"text\", ${TEXT_START_ADDR})" +SHLIB_TEXT_START_ADDR="SEGMENT_START(\"text\", ${SHLIB_TEXT_START_ADDR:-0})" +DATA_ADDR="SEGMENT_START(\"data\", ${DATA_ADDR-${DATA_SEGMENT_ALIGN}})" +SHLIB_DATA_ADDR="SEGMENT_START(\"data\", ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}})" + # if this is for an embedded system, don't add SIZEOF_HEADERS. if [ -z "$EMBEDDED" ]; then test -z "${TEXT_BASE_ADDRESS}" && TEXT_BASE_ADDRESS="${TEXT_START_ADDR} + SIZEOF_HEADERS" + SHLIB_BASE_ADDRESS="${SHLIB_TEXT_START_ADDR} + SIZEOF_HEADERS" else test -z "${TEXT_BASE_ADDRESS}" && TEXT_BASE_ADDRESS="${TEXT_START_ADDR}" + SHLIB_BASE_ADDRESS="${SHLIB_TEXT_START_ADDR}" fi cat <