This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
[RFC PATCH] Little hardening DSOs/executables against exploits
- From: Jakub Jelinek <jakub at redhat dot com>
- To: binutils at sources dot redhat dot com
- Cc: drepper at redhat dot com
- Date: Tue, 6 Jan 2004 21:17:14 +0100
- Subject: [RFC PATCH] Little hardening DSOs/executables against exploits
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
The following patch reorders the sections in the RW segment to make various
exploits a little bit harder. If ATM some exploit e.g. overflows a buffer
in .data section, it may very well overwrite .got, .got.plt etc.
With this patch, sections which are writable only because of relocation
handling come first in the RW PT_LOAD segment.
Also, it adds new ld option, -z relro, with which the linker attempts to
align the RW segment such that the area which can be read-only after
relocation processing ends on a (commonly used) page boundary (which can
be smaller than ELF maximum page size) and adds a PT_GNU_RELRO program
header which tells the dynamic linker where the RELRO area is.
The dynamic linker can decide to mprotect this area after relocation
processing.
On IA-32/AMD64 (should be doable on s390/s390x as well) also splits
.got.plt from .got section and puts .got before .got.plt. That way
.got can be in RELRO area (it is only written into during relocation
processing) and keep the .got.plt (with the exception of first 12 bytes in
it) outside of the RELRO area (as it is being written into after relocation
processing during lazy binding).
The patch doesn't move .got section on architectures with .sdata/.sbss yet.
The problem is that moving .got before .data could make the distance between
end of .sbss and .got too big and thus not reachable by the limited GOT
relative immediates. What could perhaps be done is:
a) if the whole RW segment is small enough (everything is reachable with
the machine dependent limit), move .got like on NO_SMALL_DATA arches
b) if .sbss is small enough, it could convert .sbss into SHT_PROGBITS
section, move .got to the end of RELRO area, then put .sdata and .sbss
and follow with .data etc.
c) otherwise leave .got where it is now
The question is how to write this into the linker script.
2004-01-06 Jakub Jelinek <jakub@redhat.com>
bfd/
* elf32-i386.c (elf_i386_finish_dynamic_sections): Point
DT_PLTGOT to the start of .got.plt section instead of
.got output section.
* elf64-x86-64.c (elf64_x86_64_finish_dynamic_sections): Likewise.
* 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.
* 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-02 19:13:02.000000000 +0100
+++ binutils/readelf.c 2004-01-06 17:14:44.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-05 09:47:20.000000000 +0100
@@ -3167,7 +3167,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-06 17:12:46.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-06 16:55:53.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-05 09:50:07.000000000 +0100
@@ -2667,7 +2667,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-06 16:57:09.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-06 16:41:20.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-05 09:56:57.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-05 10:38:05.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/ldlex.l.jj 2003-10-30 15:12:10.000000000 +0100
+++ ld/ldlex.l 2004-01-05 11:13:43.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-05 09:25:59.000000000 +0100
+++ ld/emultempl/elf32.em 2004-01-06 14:31:02.000000000 +0100
@@ -1645,6 +1645,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
@@ -1692,8 +1696,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\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\tCreate RELRO program header\n"));
fprintf (file, _(" -z KEYWORD\t\tIgnored for Solaris compatibility\n"));
EOF
fi
--- ld/scripttempl/elf.sc.jj 2003-10-15 17:45:41.000000000 +0200
+++ ld/scripttempl/elf.sc 2004-01-06 12:46:15.000000000 +0100
@@ -75,14 +75,27 @@ 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) }"
+ fi
+fi
DYNAMIC=".dynamic ${RELOCATING-0} : { *(.dynamic) }"
RODATA=".rodata ${RELOCATING-0} : { *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) }"
STACKNOTE="/DISCARD/ : { *(.note.GNU-stack) }"
@@ -115,7 +128,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 +227,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.*}) }
@@ -290,6 +308,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
@@ -307,6 +333,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+.data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) }}
+ ${TEXT_DYNAMIC-${DYNAMIC}}
+ ${NO_SMALL_DATA+${SEPARATE_GOTPLT+${GOT}}}
+ ${NO_SMALL_DATA+${SEPARATE_GOTPLT+.got.plt ${RELOCATING-0} : { ${DATA_SEGMENT_RELRO_GOTPLT_END} *(.got.plt) }}}
+ ${DATA_SEGMENT_RELRO_END}
+ ${NO_SMALL_DATA+${SEPARATE_GOTPLT-${GOT}}}
+
+ ${DATA_PLT+${PLT}}
+
.data ${RELOCATING-0} :
{
${RELOCATING+${DATA_START_SYMBOLS}}
@@ -314,19 +353,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-05 09:25:58.000000000 +0100
+++ ld/ldgram.y 2004-01-05 11:14:46.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-06 17:05:25.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-06 14:36:26.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-06 14:29:36.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-05 09:25:58.000000000 +0100
+++ ld/ldlang.c 2004-01-06 16:42:54.000000000 +0100
@@ -3268,7 +3268,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