This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: [RFC PATCH] Little hardening DSOs/executables against exploits (take 2)
- From: Jakub Jelinek <jakub at redhat dot com>
- To: binutils at sources dot redhat dot com, drepper at redhat dot com
- Date: Mon, 12 Jan 2004 12:38:51 +0100
- Subject: Re: [RFC PATCH] Little hardening DSOs/executables against exploits (take 2)
- References: <20040106201714.GT2020@sunsite.ms.mff.cuni.cz>
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
Below is an updated patch for the ELF DSO/executable section reshuffling
to make life harder for data section buffer overflows.
The previous patch had problems on IA-32, because elf32-i386.c assumed
in many places that _GLOBAL_OFFSET_TABLE_ is
htab->sgot->output_section->vma, while it actually is
htab->sgotplt->output_section->vma + htab->sgotplt->output_offset.
2004-01-12 Jakub Jelinek <jakub@redhat.com>
bfd/
* elf32-i386.c (elf_i386_finish_dynamic_sections): Point
DT_PLTGOT to the start of the .got.plt section instead of the
.got output section.
(elf_i386_relocate_section): Don't assume _GLOBAL_OFFSET_TABLE_
is at sgot->output_section->vma.
* elf64-x86-64.c (elf64_x86_64_finish_dynamic_sections): Point
DT_PLTGOT to the start of the .got.plt section instead of the
.got output section.
(elf64_x86_64_relocate_section): Don't assume _GLOBAL_OFFSET_TABLE_
is at sgot->output_section->vma.
* elf.c (_bfd_elf_print_private_bfd_data): Handle PT_GNU_RELRO.
(bfd_section_from_phdr): Likewise.
(map_sections_to_segments): Likewise.
(assign_file_positions_for_segments): Likewise.
(get_program_header_size): Likewise.
* elflink.h (size_dynamic_sections): Set elf_tdata (output_bfd)->relro
from info->relro.
* elf-bfd.h (struct elf_obj_tdata): Add relro field.
include/
* bfdlink.h (struct bfd_link_info): Add relro, relro_start and
relro_end fields.
* elf/common.h (PT_GNU_EH_FRAME, PT_GNU_STACK): Add comments.
(PT_GNU_RELRO): Define.
binutils/
* readelf.c (get_segment_type): Handle PT_GNU_RELRO.
ld/
* emulparams/elf_i386.sh (SEPARATE_GOTPLT): Set.
* emulparams/elf_x86_64.sh (SEPARATE_GOTPLT): Set.
* ldlex.l (DATA_SEGMENT_RELRO_END): Add.
* emultempl/elf32.em (gld${EMULATION_NAME}_handle_option): Handle
-z relro and -z norelro.
(gld${EMULATION_NAME}_list_options): Add it to usage.
* scripttempl/elf.sc: Create separate .got.plt section if
SEPARATE_GOTPLT. Move sections which are only written during
relocation handling to the beginning of RW segment. If
NO_SMALL_DATA, move .got before .data. Add DATA_SEGMENT_RELRO_END
directive.
* ldgram.y (DATA_SEGMENT_RELRO_END): Add.
* ldexp.c (exp_print_token): Handle DATA_SEGMENT_RELRO_END.
(fold_unary): Likewise.
(fold_binary): Handle -z relro.
* ldexp.h (struct exp_data_seg): Add exp_dataseg_relro_seen and
exp_dataseg_relro_adjust phases. Add relro_end field.
* ldmain.c (main): Initialize link_info.relro to FALSE.
* ldlang.c (lang_size_sections): Handle -z relro.
--- binutils/readelf.c.jj 2004-01-12 10:08:00.000000000 +0100
+++ binutils/readelf.c 2004-01-12 12:00:49.000000000 +0100
@@ -2144,6 +2144,7 @@ get_segment_type (unsigned long p_type)
case PT_GNU_EH_FRAME:
return "GNU_EH_FRAME";
case PT_GNU_STACK: return "STACK";
+ case PT_GNU_RELRO: return "GNU_RELRO";
default:
if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC))
--- bfd/elf32-i386.c.jj 2004-01-02 19:13:01.000000000 +0100
+++ bfd/elf32-i386.c 2004-01-12 14:04:50.000000000 +0100
@@ -2269,24 +2269,29 @@ elf_i386_relocate_section (bfd *output_b
if (off >= (bfd_vma) -2)
abort ();
- relocation = htab->sgot->output_offset + off;
+ relocation = htab->sgot->output_section->vma
+ + htab->sgot->output_offset + off
+ - htab->sgotplt->output_section->vma
+ - htab->sgotplt->output_offset;
break;
case R_386_GOTOFF:
/* Relocation is relative to the start of the global offset
table. */
- /* Note that sgot->output_offset is not involved in this
- calculation. We always want the start of .got. If we
- defined _GLOBAL_OFFSET_TABLE in a different way, as is
+ /* Note that sgot is not involved in this
+ calculation. We always want the start of .got.plt. If we
+ defined _GLOBAL_OFFSET_TABLE_ in a different way, as is
permitted by the ABI, we might have to change this
calculation. */
- relocation -= htab->sgot->output_section->vma;
+ relocation -= htab->sgotplt->output_section->vma
+ + htab->sgotplt->output_offset;
break;
case R_386_GOTPC:
/* Use global offset table as symbol value. */
- relocation = htab->sgot->output_section->vma;
+ relocation = htab->sgotplt->output_section->vma
+ + htab->sgotplt->output_offset;
unresolved_reloc = FALSE;
break;
@@ -2707,12 +2712,15 @@ elf_i386_relocate_section (bfd *output_b
abort ();
if (r_type == ELF32_R_TYPE (rel->r_info))
{
- relocation = htab->sgot->output_offset + off;
+ bfd_vma g_o_t = htab->sgotplt->output_section->vma
+ + htab->sgotplt->output_offset;
+ relocation = htab->sgot->output_section->vma
+ + htab->sgot->output_offset + off - g_o_t;
if ((r_type == R_386_TLS_IE || r_type == R_386_TLS_GOTIE)
&& tls_type == GOT_TLS_IE_BOTH)
relocation += 4;
if (r_type == R_386_TLS_IE)
- relocation += htab->sgot->output_section->vma;
+ relocation += g_o_t;
unresolved_reloc = FALSE;
}
else
@@ -2769,7 +2777,11 @@ elf_i386_relocate_section (bfd *output_b
if (tls_type == GOT_TLS_IE_BOTH)
off += 4;
}
- bfd_put_32 (output_bfd, htab->sgot->output_offset + off,
+ bfd_put_32 (output_bfd,
+ htab->sgot->output_section->vma
+ + htab->sgot->output_offset + off
+ - htab->sgotplt->output_section->vma
+ - htab->sgotplt->output_offset,
contents + roff + 8);
/* Skip R_386_PLT32. */
rel++;
@@ -2831,7 +2843,10 @@ elf_i386_relocate_section (bfd *output_b
bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
htab->tls_ldm_got.offset |= 1;
}
- relocation = htab->sgot->output_offset + off;
+ relocation = htab->sgot->output_section->vma
+ + htab->sgot->output_offset + off
+ - htab->sgotplt->output_section->vma
+ - htab->sgotplt->output_offset;
unresolved_reloc = FALSE;
break;
@@ -3167,7 +3182,8 @@ elf_i386_finish_dynamic_sections (bfd *o
continue;
case DT_PLTGOT:
- dyn.d_un.d_ptr = htab->sgot->output_section->vma;
+ s = htab->sgotplt;
+ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
break;
case DT_JMPREL:
--- bfd/elf.c.jj 2003-12-22 10:54:05.000000000 +0100
+++ bfd/elf.c 2004-01-12 12:00:49.000000000 +0100
@@ -967,6 +967,7 @@ _bfd_elf_print_private_bfd_data (bfd *ab
case PT_TLS: pt = "TLS"; break;
case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
case PT_GNU_STACK: pt = "STACK"; break;
+ case PT_GNU_RELRO: pt = "RELRO"; break;
default: sprintf (buf, "0x%lx", p->p_type); pt = buf; break;
}
fprintf (f, "%8s off 0x", pt);
@@ -2291,6 +2292,9 @@ bfd_section_from_phdr (bfd *abfd, Elf_In
case PT_GNU_STACK:
return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "stack");
+ case PT_GNU_RELRO:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "relro");
+
default:
/* Check for any processor-specific program segment types.
If no handler for them, default to making "segment" sections. */
@@ -3501,6 +3505,21 @@ map_sections_to_segments (bfd *abfd)
pm = &m->next;
}
+ if (elf_tdata (abfd)->relro)
+ {
+ amt = sizeof (struct elf_segment_map);
+ m = bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_GNU_RELRO;
+ m->p_flags = PF_R;
+ m->p_flags_valid = 1;
+
+ *pm = m;
+ pm = &m->next;
+ }
+
free (sections);
sections = NULL;
@@ -4002,6 +4021,37 @@ Error: First section in segment (%s) sta
if (! m->p_paddr_valid)
p->p_paddr = phdrs_paddr;
}
+ else if (p->p_type == PT_GNU_RELRO)
+ {
+ Elf_Internal_Phdr *lp;
+
+ for (lp = phdrs; lp < phdrs + count; ++lp)
+ {
+ if (lp->p_type == PT_LOAD
+ && lp->p_vaddr <= link_info->relro_start
+ && lp->p_vaddr + lp->p_filesz
+ >= link_info->relro_end)
+ break;
+ }
+
+ if (lp < phdrs + count
+ && link_info->relro_end > link_info->relro_start)
+ {
+ bfd_vma diff = link_info->relro_start - lp->p_vaddr;
+ p->p_vaddr = lp->p_vaddr + diff;
+ p->p_paddr = lp->p_paddr + diff;
+ p->p_offset = lp->p_offset + diff;
+ p->p_filesz = link_info->relro_end - link_info->relro_start;
+ p->p_memsz = p->p_filesz;
+ p->p_align = 1;
+ p->p_flags = (lp->p_flags & ~PF_W);
+ }
+ else
+ {
+ memset (p, 0, sizeof *p);
+ p->p_type = PT_NULL;
+ }
+ }
}
}
@@ -4089,6 +4139,12 @@ get_program_header_size (bfd *abfd)
++segs;
}
+ if (elf_tdata (abfd)->relro)
+ {
+ /* We need a PT_GNU_RELRO segment. */
+ ++segs;
+ }
+
for (s = abfd->sections; s != NULL; s = s->next)
{
if ((s->flags & SEC_LOAD) != 0
--- bfd/elflink.h.jj 2004-01-02 19:13:02.000000000 +0100
+++ bfd/elflink.h 2004-01-12 12:00:49.000000000 +0100
@@ -1909,6 +1909,7 @@ NAME(bfd_elf,size_dynamic_sections) (bfd
if (!is_elf_hash_table (info->hash))
return TRUE;
+ elf_tdata (output_bfd)->relro = info->relro;
if (info->execstack)
elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X;
else if (info->noexecstack)
--- bfd/elf64-x86-64.c.jj 2003-12-22 10:49:42.000000000 +0100
+++ bfd/elf64-x86-64.c 2004-01-12 14:27:11.000000000 +0100
@@ -1919,9 +1919,11 @@ elf64_x86_64_relocate_section (bfd *outp
if (off >= (bfd_vma) -2)
abort ();
- relocation = htab->sgot->output_offset + off;
- if (r_type == R_X86_64_GOTPCREL)
- relocation += htab->sgot->output_section->vma;
+ relocation = htab->sgot->output_section->vma
+ + htab->sgot->output_offset + off;
+ if (r_type != R_X86_64_GOTPCREL)
+ relocation -= htab->sgotplt->output_section->vma
+ - htab->sgotplt->output_offset;
break;
@@ -2667,7 +2669,8 @@ elf64_x86_64_finish_dynamic_sections (bf
continue;
case DT_PLTGOT:
- dyn.d_un.d_ptr = htab->sgot->output_section->vma;
+ s = htab->sgotplt;
+ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
break;
case DT_JMPREL:
--- bfd/elf-bfd.h.jj 2003-12-22 10:54:05.000000000 +0100
+++ bfd/elf-bfd.h 2004-01-12 12:00:49.000000000 +0100
@@ -1202,6 +1202,9 @@ struct elf_obj_tdata
/* Segment flags for the PT_GNU_STACK segment. */
unsigned int stack_flags;
+ /* Should the PT_GNU_RELRO segment be emitted? */
+ bfd_boolean relro;
+
/* Symbol version definitions in external objects. */
Elf_Internal_Verdef *verdef;
--- include/bfdlink.h.jj 2003-12-22 10:55:57.000000000 +0100
+++ include/bfdlink.h 2004-01-12 12:00:49.000000000 +0100
@@ -302,6 +302,9 @@ struct bfd_link_info
flags. */
unsigned int noexecstack: 1;
+ /* TRUE if PT_GNU_RELRO segment should be created. */
+ unsigned int relro: 1;
+
/* What to do with unresolved symbols in an object file.
When producing static binaries the default is GENERATE_ERROR.
When producing dynamic binaries the default is IGNORE. The
@@ -386,6 +389,9 @@ struct bfd_link_info
/* May be used to set DT_FLAGS_1 for ELF. */
bfd_vma flags_1;
+
+ /* Start and end of RELRO region. */
+ bfd_vma relro_start, relro_end;
};
/* This structures holds a set of callback functions. These are
--- include/elf/common.h.jj 2003-12-22 10:49:49.000000000 +0100
+++ include/elf/common.h 2004-01-12 12:00:49.000000000 +0100
@@ -287,8 +287,9 @@
#define PT_LOPROC 0x70000000 /* Processor-specific */
#define PT_HIPROC 0x7FFFFFFF /* Processor-specific */
-#define PT_GNU_EH_FRAME (PT_LOOS + 0x474e550)
-#define PT_GNU_STACK (PT_LOOS + 0x474e551)
+#define PT_GNU_EH_FRAME (PT_LOOS + 0x474e550) /* Frame unwind information */
+#define PT_GNU_STACK (PT_LOOS + 0x474e551) /* Stack flags */
+#define PT_GNU_RELRO (PT_LOOS + 0x474e552) /* Read-only after relocation */
/* Program segment permissions, in program header p_flags field. */
--- ld/emulparams/elf_i386.sh.jj 2003-05-30 17:19:17.000000000 +0200
+++ ld/emulparams/elf_i386.sh 2004-01-12 12:00:49.000000000 +0100
@@ -11,3 +11,4 @@ TEMPLATE_NAME=elf32
GENERATE_SHLIB_SCRIPT=yes
GENERATE_PIE_SCRIPT=yes
NO_SMALL_DATA=yes
+SEPARATE_GOTPLT=12
--- ld/emulparams/elf_x86_64.sh.jj 2003-05-30 17:19:17.000000000 +0200
+++ ld/emulparams/elf_x86_64.sh 2004-01-12 12:00:49.000000000 +0100
@@ -12,6 +12,7 @@ TEMPLATE_NAME=elf32
GENERATE_SHLIB_SCRIPT=yes
GENERATE_PIE_SCRIPT=yes
NO_SMALL_DATA=yes
+SEPARATE_GOTPLT=24
if [ "x${host}" = "x${target}" ]; then
case " $EMULATION_LIBPATH " in
--- ld/ldlex.l.jj 2004-01-12 11:53:40.000000000 +0100
+++ ld/ldlex.l 2004-01-12 12:00:49.000000000 +0100
@@ -254,6 +254,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([
<BOTH,SCRIPT>"LENGTH" { RTOKEN(LENGTH);}
<EXPRESSION,BOTH,SCRIPT>"ALIGN" { RTOKEN(ALIGN_K);}
<EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_ALIGN" { RTOKEN(DATA_SEGMENT_ALIGN);}
+<EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_RELRO_END" { RTOKEN(DATA_SEGMENT_RELRO_END);}
<EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_END" { RTOKEN(DATA_SEGMENT_END);}
<EXPRESSION,BOTH,SCRIPT>"ADDR" { RTOKEN(ADDR);}
<EXPRESSION,BOTH,SCRIPT>"LOADADDR" { RTOKEN(LOADADDR);}
--- ld/emultempl/elf32.em.jj 2004-01-12 11:53:40.000000000 +0100
+++ ld/emultempl/elf32.em 2004-01-12 12:00:49.000000000 +0100
@@ -1646,6 +1646,10 @@ cat >>e${EMULATION_NAME}.c <<EOF
link_info.noexecstack = TRUE;
link_info.execstack = FALSE;
}
+ else if (strcmp (optarg, "relro") == 0)
+ link_info.relro = TRUE;
+ else if (strcmp (optarg, "norelro") == 0)
+ link_info.relro = FALSE;
/* What about the other Solaris -z options? FIXME. */
break;
EOF
@@ -1693,8 +1697,10 @@ cat >>e${EMULATION_NAME}.c <<EOF
fprintf (file, _(" -z nodlopen\t\tMark DSO not available to dlopen\n"));
fprintf (file, _(" -z nodump\t\tMark DSO not available to dldump\n"));
fprintf (file, _(" -z noexecstack\tMark executable as not requiring executable stack\n"));
+ fprintf (file, _(" -z norelro\t\tDon't create RELRO program header\n"));
fprintf (file, _(" -z now\t\tMark object non-lazy runtime binding\n"));
fprintf (file, _(" -z origin\t\tMark object requiring immediate \$ORIGIN processing\n\t\t\t at runtime\n"));
+ fprintf (file, _(" -z relro\t\tCreate RELRO program header\n"));
fprintf (file, _(" -z KEYWORD\t\tIgnored for Solaris compatibility\n"));
EOF
fi
--- ld/scripttempl/elf.sc.jj 2004-01-12 11:53:40.000000000 +0100
+++ ld/scripttempl/elf.sc 2004-01-12 12:00:49.000000000 +0100
@@ -75,16 +75,31 @@ test "$LD_FLAG" = "N" && DATA_ADDR=.
test -n "$CREATE_SHLIB$CREATE_PIE" && test -n "$SHLIB_DATA_ADDR" && COMMONPAGESIZE=""
test -z "$CREATE_SHLIB$CREATE_PIE" && test -n "$DATA_ADDR" && COMMONPAGESIZE=""
DATA_SEGMENT_ALIGN="ALIGN(${SEGMENT_SIZE}) + (. & (${MAXPAGESIZE} - 1))"
+DATA_SEGMENT_RELRO_END=""
+DATA_SEGMENT_RELRO_GOTPLT_END=""
DATA_SEGMENT_END=""
if test -n "${COMMONPAGESIZE}"; then
DATA_SEGMENT_ALIGN="ALIGN (${SEGMENT_SIZE}) - ((${MAXPAGESIZE} - .) & (${MAXPAGESIZE} - 1)); . = DATA_SEGMENT_ALIGN (${MAXPAGESIZE}, ${COMMONPAGESIZE})"
DATA_SEGMENT_END=". = DATA_SEGMENT_END (.);"
+ if test -n "${SEPARATE_GOTPLT}"; then
+ DATA_SEGMENT_RELRO_GOTPLT_END=". = DATA_SEGMENT_RELRO_END (. + ${SEPARATE_GOTPLT});"
+ else
+ DATA_SEGMENT_RELRO_END=". = DATA_SEGMENT_RELRO_END (.);"
+ fi
fi
INTERP=".interp ${RELOCATING-0} : { *(.interp) }"
PLT=".plt ${RELOCATING-0} : { *(.plt) }"
-test -z "$GOT" && GOT=".got ${RELOCATING-0} : { *(.got.plt) *(.got) }"
+if test -z "$GOT"; then
+ if test -z "$SEPARATE_GOTPLT"; then
+ GOT=".got ${RELOCATING-0} : { *(.got.plt) *(.got) }"
+ else
+ GOT=".got ${RELOCATING-0} : { *(.got) }"
+ GOTPLT=".got.plt ${RELOCATING-0} : { ${RELOCATING+${DATA_SEGMENT_RELRO_GOTPLT_END}} *(.got.plt) }"
+ fi
+fi
DYNAMIC=".dynamic ${RELOCATING-0} : { *(.dynamic) }"
RODATA=".rodata ${RELOCATING-0} : { *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) }"
+DATARELRO=".data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) }"
STACKNOTE="/DISCARD/ : { *(.note.GNU-stack) }"
if test -z "${NO_SMALL_DATA}"; then
SBSS=".sbss ${RELOCATING-0} :
@@ -115,7 +130,10 @@ if test -z "${NO_SMALL_DATA}"; then
.rela.sdata2 ${RELOCATING-0} : { *(.rela.sdata2${RELOCATING+ .rela.sdata2.* .rela.gnu.linkonce.s2.*}) }"
REL_SBSS2=".rel.sbss2 ${RELOCATING-0} : { *(.rel.sbss2${RELOCATING+ .rel.sbss2.* .rel.gnu.linkonce.sb2.*}) }
.rela.sbss2 ${RELOCATING-0} : { *(.rela.sbss2${RELOCATING+ .rela.sbss2.* .rela.gnu.linkonce.sb2.*}) }"
+else
+ NO_SMALL_DATA=" "
fi
+test -n "$SEPARATE_GOTPLT" && SEPARATE_GOTPLT=" "
CTOR=".ctors ${CONSTRUCTING-0} :
{
${CONSTRUCTING+${CTOR_START}}
@@ -211,6 +229,8 @@ eval $COMBRELOCCAT <<EOF
.rel.rodata ${RELOCATING-0} : { *(.rel.rodata${RELOCATING+ .rel.rodata.* .rel.gnu.linkonce.r.*}) }
.rela.rodata ${RELOCATING-0} : { *(.rela.rodata${RELOCATING+ .rela.rodata.* .rela.gnu.linkonce.r.*}) }
${OTHER_READONLY_RELOC_SECTIONS}
+ .rel.data.rel.ro ${RELOCATING-0} : { *(.rel.data.rel.ro${RELOCATING+*}) }
+ .rela.data.rel.ro ${RELOCATING-0} : { *(.rel.data.rel.ro${RELOCATING+*}) }
.rel.data ${RELOCATING-0} : { *(.rel.data${RELOCATING+ .rel.data.* .rel.gnu.linkonce.d.*}) }
.rela.data ${RELOCATING-0} : { *(.rela.data${RELOCATING+ .rela.data.* .rela.gnu.linkonce.d.*}) }
.rel.tdata ${RELOCATING-0} : { *(.rel.tdata${RELOCATING+ .rel.tdata.* .rel.gnu.linkonce.td.*}) }
@@ -292,6 +312,14 @@ cat <<EOF
${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}};}}
${CREATE_PIE+${RELOCATING+. = ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}};}}
+ /* Exception handling */
+ .eh_frame ${RELOCATING-0} : { KEEP (*(.eh_frame)) }
+ .gcc_except_table ${RELOCATING-0} : { *(.gcc_except_table) }
+
+ /* Thread Local Storage sections */
+ .tdata ${RELOCATING-0} : { *(.tdata${RELOCATING+ .tdata.* .gnu.linkonce.td.*}) }
+ .tbss ${RELOCATING-0} : { *(.tbss${RELOCATING+ .tbss.* .gnu.linkonce.tb.*})${RELOCATING+ *(.tcommon)} }
+
/* Ensure the __preinit_array_start label is properly aligned. We
could instead move the label definition inside the section, but
the linker would then create the section even if it turns out to
@@ -309,6 +337,19 @@ cat <<EOF
.fini_array ${RELOCATING-0} : { *(.fini_array) }
${RELOCATING+${CREATE_SHLIB-PROVIDE (__fini_array_end = .);}}
+ ${RELOCATING+${CTOR}}
+ ${RELOCATING+${DTOR}}
+ .jcr ${RELOCATING-0} : { KEEP (*(.jcr)) }
+
+ ${RELOCATING+${DATARELRO}}
+ ${TEXT_DYNAMIC-${DYNAMIC}}
+ ${NO_SMALL_DATA+${SEPARATE_GOTPLT+${GOT}}}
+ ${NO_SMALL_DATA+${SEPARATE_GOTPLT+${GOTPLT}}}
+ ${RELOCATING+${DATA_SEGMENT_RELRO_END}}
+ ${NO_SMALL_DATA+${SEPARATE_GOTPLT-${GOT}}}
+
+ ${DATA_PLT+${PLT}}
+
.data ${RELOCATING-0} :
{
${RELOCATING+${DATA_START_SYMBOLS}}
@@ -316,19 +357,10 @@ cat <<EOF
${CONSTRUCTING+SORT(CONSTRUCTORS)}
}
.data1 ${RELOCATING-0} : { *(.data1) }
- .tdata ${RELOCATING-0} : { *(.tdata${RELOCATING+ .tdata.* .gnu.linkonce.td.*}) }
- .tbss ${RELOCATING-0} : { *(.tbss${RELOCATING+ .tbss.* .gnu.linkonce.tb.*})${RELOCATING+ *(.tcommon)} }
- .eh_frame ${RELOCATING-0} : { KEEP (*(.eh_frame)) }
- .gcc_except_table ${RELOCATING-0} : { *(.gcc_except_table) }
${WRITABLE_RODATA+${RODATA}}
${OTHER_READWRITE_SECTIONS}
- ${TEXT_DYNAMIC-${DYNAMIC}}
- ${RELOCATING+${CTOR}}
- ${RELOCATING+${DTOR}}
- .jcr ${RELOCATING-0} : { KEEP (*(.jcr)) }
- ${DATA_PLT+${PLT}}
${RELOCATING+${OTHER_GOT_SYMBOLS}}
- ${GOT}
+ ${NO_SMALL_DATA-${GOT}}
${OTHER_GOT_SECTIONS}
${CREATE_SHLIB+${SDATA2}}
${CREATE_SHLIB+${SBSS2}}
--- ld/ldgram.y.jj 2004-01-12 11:56:21.000000000 +0100
+++ ld/ldgram.y 2004-01-12 12:00:49.000000000 +0100
@@ -128,7 +128,7 @@ static int error_index;
%token END
%left <token> '('
%token <token> ALIGN_K BLOCK BIND QUAD SQUAD LONG SHORT BYTE
-%token SECTIONS PHDRS SORT DATA_SEGMENT_ALIGN DATA_SEGMENT_END
+%token SECTIONS PHDRS SORT DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END DATA_SEGMENT_END
%token '{' '}'
%token SIZEOF_HEADERS OUTPUT_FORMAT FORCE_COMMON_ALLOCATION OUTPUT_ARCH
%token INHIBIT_COMMON_ALLOCATION
@@ -803,6 +803,8 @@ exp :
{ $$ = exp_unop(ALIGN_K,$3); }
| DATA_SEGMENT_ALIGN '(' exp ',' exp ')'
{ $$ = exp_binop (DATA_SEGMENT_ALIGN, $3, $5); }
+ | DATA_SEGMENT_RELRO_END '(' exp ')'
+ { $$ = exp_unop(DATA_SEGMENT_RELRO_END, $3); }
| DATA_SEGMENT_END '(' exp ')'
{ $$ = exp_unop(DATA_SEGMENT_END, $3); }
| BLOCK '(' exp ')'
--- ld/ldexp.c.jj 2004-01-05 09:25:57.000000000 +0100
+++ ld/ldexp.c 2004-01-12 12:00:49.000000000 +0100
@@ -101,6 +101,7 @@ exp_print_token (token_code_type code, i
{ MAX_K, "MAX_K" },
{ REL, "relocatable" },
{ DATA_SEGMENT_ALIGN, "DATA_SEGMENT_ALIGN" },
+ { DATA_SEGMENT_RELRO_END, "DATA_SEGMENT_RELRO_END" },
{ DATA_SEGMENT_END, "DATA_SEGMENT_END" }
};
unsigned int idx;
@@ -275,14 +276,36 @@ fold_unary (etree_type *tree,
result.valid_p = FALSE;
break;
+ case DATA_SEGMENT_RELRO_END:
+ if (allocation_done != lang_first_phase_enum
+ && (exp_data_seg.phase == exp_dataseg_align_seen
+ || exp_data_seg.phase == exp_dataseg_adjust
+ || exp_data_seg.phase == exp_dataseg_relro_adjust
+ || allocation_done != lang_allocating_phase_enum))
+ {
+ if (exp_data_seg.phase == exp_dataseg_align_seen
+ || exp_data_seg.phase == exp_dataseg_relro_adjust)
+ exp_data_seg.relro_end
+ = result.value + current_section->bfd_section->vma;
+ if (exp_data_seg.phase == exp_dataseg_align_seen)
+ exp_data_seg.phase = exp_dataseg_relro_seen;
+ result.value = dot - current_section->bfd_section->vma;
+ }
+ else
+ result.valid_p = FALSE;
+ break;
+
case DATA_SEGMENT_END:
if (allocation_done != lang_first_phase_enum
&& current_section == abs_output_section
&& (exp_data_seg.phase == exp_dataseg_align_seen
+ || exp_data_seg.phase == exp_dataseg_relro_seen
|| exp_data_seg.phase == exp_dataseg_adjust
+ || exp_data_seg.phase == exp_dataseg_relro_adjust
|| allocation_done != lang_allocating_phase_enum))
{
- if (exp_data_seg.phase == exp_dataseg_align_seen)
+ if (exp_data_seg.phase == exp_dataseg_align_seen
+ || exp_data_seg.phase == exp_dataseg_relro_seen)
{
exp_data_seg.phase = exp_dataseg_end_seen;
exp_data_seg.end = result.value;
@@ -399,12 +422,23 @@ fold_binary (etree_type *tree,
&& current_section == abs_output_section
&& (exp_data_seg.phase == exp_dataseg_none
|| exp_data_seg.phase == exp_dataseg_adjust
+ || exp_data_seg.phase == exp_dataseg_relro_adjust
|| allocation_done != lang_allocating_phase_enum))
{
bfd_vma maxpage = result.value;
result.value = align_n (dot, maxpage);
- if (exp_data_seg.phase != exp_dataseg_adjust)
+ if (exp_data_seg.phase == exp_dataseg_relro_adjust)
+ {
+ /* Attempt to align DATA_SEGMENT_RELRO_END at
+ a common page boundary. */
+ bfd_vma relro;
+
+ relro = exp_data_seg.relro_end - exp_data_seg.base;
+ result.value += -relro & (other.value - 1);
+ exp_data_seg.base = result.value;
+ }
+ else if (exp_data_seg.phase != exp_dataseg_adjust)
{
result.value += dot & (maxpage - 1);
if (allocation_done == lang_allocating_phase_enum)
@@ -412,6 +446,7 @@ fold_binary (etree_type *tree,
exp_data_seg.phase = exp_dataseg_align_seen;
exp_data_seg.base = result.value;
exp_data_seg.pagesize = other.value;
+ exp_data_seg.relro_end = 0;
}
}
else if (other.value < maxpage)
--- ld/ldexp.h.jj 2004-01-05 09:25:57.000000000 +0100
+++ ld/ldexp.h 2004-01-12 12:00:49.000000000 +0100
@@ -95,10 +95,12 @@ extern struct exp_data_seg {
enum {
exp_dataseg_none,
exp_dataseg_align_seen,
+ exp_dataseg_relro_seen,
exp_dataseg_end_seen,
+ exp_dataseg_relro_adjust,
exp_dataseg_adjust
} phase;
- bfd_vma base, end, pagesize;
+ bfd_vma base, relro_end, end, pagesize;
} exp_data_seg;
typedef struct _fill_type fill_type;
--- ld/ldmain.c.jj 2003-12-22 10:49:49.000000000 +0100
+++ ld/ldmain.c 2004-01-12 12:00:49.000000000 +0100
@@ -299,6 +299,7 @@ main (int argc, char **argv)
link_info.new_dtags = FALSE;
link_info.combreloc = TRUE;
link_info.eh_frame_hdr = FALSE;
+ link_info.relro = FALSE;
link_info.strip_discarded = TRUE;
link_info.strip = strip_none;
link_info.discard = discard_sec_merge;
--- ld/ldlang.c.jj 2004-01-12 11:56:52.000000000 +0100
+++ ld/ldlang.c 2004-01-12 12:00:49.000000000 +0100
@@ -3360,7 +3360,19 @@ lang_size_sections
exp_data_seg.phase = exp_dataseg_none;
result = lang_size_sections_1 (s, output_section_statement, prev, fill,
dot, relax, check_regions);
- if (exp_data_seg.phase == exp_dataseg_end_seen)
+ if (exp_data_seg.phase == exp_dataseg_end_seen
+ && link_info.relro && exp_data_seg.relro_end)
+ {
+ /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END pair was seen, try
+ to put exp_data_seg.relro on a (common) page boundary. */
+
+ exp_data_seg.phase = exp_dataseg_relro_adjust;
+ result = lang_size_sections_1 (s, output_section_statement, prev, fill,
+ dot, relax, check_regions);
+ link_info.relro_start = exp_data_seg.base;
+ link_info.relro_end = exp_data_seg.relro_end;
+ }
+ else if (exp_data_seg.phase == exp_dataseg_end_seen)
{
/* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether
a page could be saved in the data segment. */
Jakub