| /* 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.gnu.build-id : { |
| *(.note.gnu.build-id) |
| } :rodata :note |
| .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; |
| stack PT_GNU_STACK FLAGS(6); /* RW- */ |
| } |