/* Copyright 2016 The Fuchsia Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ /* * This is a linker script for producing a DSO (shared library) image * that is entirely read-only and trivial to map in without using a * proper ELF loader. It has two segments: read-only starting at the * beginning of the file, and executable code page-aligned and marked * by the (hidden) symbols CODE_START and CODE_END. * * Ideally this could be accomplished without an explicit linker * script. The linker would need an option to make the .dynamic * section (aka PT_DYNAMIC segment) read-only rather than read-write; * in fact that could be the default for Zircon/Fuchsia or for * anything using a dynamic linker like musl's that doesn't try to * write into the .dynamic section at runtime (for -shared that is; * for -pie and dynamically-linked executables there is the DT_DEBUG * question). The linker would need a second option to entirely * segregate code from rodata (and from non-loaded parts of the file), * and page-align the code segment (and pad the end to a page * boundary); in fact that could be the default for any system that * wants to minimize what can go into pages mapped with execute * permission, which is a worthwhile trade-off of security mitigation * over tiny amounts of wasted space in the ELF file. Beyond that, * the linker should not generate the .got* or .plt* sections at all * when there are no relocs being generated, but today's linkers still * do; since some of those sections are writable, they cause the * creation of a writable PT_LOAD segment by normal linker logic. */ SECTIONS { . = 0 + SIZEOF_HEADERS; /* * This should be defined automatically by the linker. * But LLD fails to do so in the presence of a linker script. * So define it explicitly. * TODO(mcgrathr): If http://bugs.llvm.org/show_bug.cgi?id=32367 * is ever fixed, remove this. */ PROVIDE_HIDDEN(__ehdr_start = . - SIZEOF_HEADERS); /* * Match the non-allocated Gold version note specially, so * it doesn't go into the allocated .note section below. * With BFD ld, the .note clause could use: * INPUT_SECTION_FLAGS(SHF_ALLOC) *(.note*) * so as not to match any non-allocated note sections generically. * But gold and lld do not support the INPUT_SECTION_FLAGS keyword. */ .note.gnu.gold-version : { *(.note.gnu.gold-version) } .note : { *(.note*) } :rodata :note .dynamic : { *(.dynamic) } :rodata :dynamic .hash : { *(.hash) } :rodata .gnu.hash : { *(.gnu.hash) } .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } :rodata .rodata1 : { *(.rodata1) } .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } :rodata :eh_frame_hdr .eh_frame : { KEEP(*(.eh_frame)) *(.eh_frame.*) } :rodata .gcc_except_table : { *(.gcc_except_table*) } .gnu_extab : { *(.gnu_extab*) } /* * We'd like to discard these linker-generated sections with /DISCARD/ * (or convince the linker not to generate them at all). * But the linker doesn't know how to do that. */ .got : { *(.got*) } .plt : { *(.plt*) } /* * This section will only exist if there were some dynamic relocation * sections generated by the linker. If this happens, the code is * broken (it uses PC-sensitive static initializers or suchlike). */ .norelocs : { *(.rel*) } ASSERT(SIZEOF(.norelocs) == 0, "rodso code must avoid dynamic relocations!") /* * Likewise, this will only exist if there was some writable data. */ .nodata : { *(.data*) *(.sdata*) *(.bss*) *(.sbss*) } ASSERT(SIZEOF(.nodata) == 0, "rodso code must avoid writable data sections!") . = ALIGN(CONSTANT(MAXPAGESIZE)); .text : { *(.text.unlikely .text.*_unlikely .text.unlikely.*) *(.text.exit .text.exit.*) *(.text.startup .text.startup.*) *(.text.hot .text.hot.*) *(.text .stub .text.* .gnu.linkonce.t.*) *(.init .init.* .fini .fini.*) *(.gnu.warning) *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx) PROVIDE_HIDDEN(_end = .); /* * Pad out the code segment to a page boundary, so that there * is only nop or zero padding visible in the memory image * rather than seeing non-loaded portions of the ELF file * (.shstrtab, section headers, .symtab if not stripped, etc.). */ . = ALIGN(CONSTANT(MAXPAGESIZE)); } :code } PHDRS { rodata PT_LOAD FLAGS(4) FILEHDR PHDRS; code PT_LOAD FLAGS(5); dynamic PT_DYNAMIC FLAGS(4); note PT_NOTE; eh_frame_hdr PT_GNU_EH_FRAME; }