diff options
author | Russ Dill <Russ.Dill@ti.com> | 2013-09-17 01:10:23 -0700 |
---|---|---|
committer | 黄涛 <huangtao@rock-chips.com> | 2013-11-21 13:39:21 +0800 |
commit | 2ecab0b339252a6427b52d03719c96f97f19e272 (patch) | |
tree | 0b325933675512e6cd238861c949ca1bc7979561 /pie | |
parent | 49d083bd72f8fe93b1d76078be1da897f5e41e98 (diff) |
PIE: Support embedding position independent executables
This commit adds support for embedding PIEs into the kernel, loading them
into genalloc sections, performing necessary relocations, and running code
from them. This allows platforms that need to run code from SRAM, such
an during suspend/resume, to develop that code in C instead of assembly.
Functions and data for each PIE should be grouped into sections with the
__pie(<group>) and __pie_data(<group>) macros respectively. Any symbols or
functions that are to be accessed from outside the PIE should be marked with
EXPORT_PIE_SYMBOL(<sym>). For example:
static struct ddr_timings xyz_timings __pie_data(platformxyz) = {
[...]
};
void __pie(platformxyz) xyz_ddr_on(void *addr)
{
[...]
}
EXPORT_PIE_SYMBOL(xyz_ddr_on);
While the kernel can access exported symbols from the PIE, the PIE cannot
access symbols from the kernel, but can access data from the kernel and
call functions in the kernel so long as addresses are passed into the PIE.
PIEs are loaded from the kernel into a genalloc pool with pie_load_sections.
pie_load_sections allocates space within the pool, copies the neccesary
code/data, and performs any necessary relocations. A chunk identifier is
returned for removing the PIE from the pool, and for translating symbols.
Because the PIEs are dynamically relocated, special accessors must be used
to access PIE symbols from kernel code:
- kern_to_pie(chunk, ptr): Translate a PIE symbol to the virtual address
it is loaded into within the pool.
- fn_to_pie(chunk, ptr): Same as above, but for function pointers.
- sram_to_phys(chunk, addr): Translate a virtual address within a loaded PIE
to a physical address.
Loading a PIE involves three main steps. First a set of common functions to
cover built-ins emitted by gcc (memcpy, memmove, etc) is copied into the pool.
Then the actual PIE code and data is copied into the pool. Because the PIE
code is contained within an overlay with other PIEs, offsets to the common
functions are maintained. Finally, relocations are performed as necessary.
Signed-off-by: Russ Dill <Russ.Dill@ti.com>
Diffstat (limited to 'pie')
-rw-r--r-- | pie/.gitignore | 3 | ||||
-rw-r--r-- | pie/Makefile | 85 |
2 files changed, 88 insertions, 0 deletions
diff --git a/pie/.gitignore b/pie/.gitignore new file mode 100644 index 000000000000..4f298035927b --- /dev/null +++ b/pie/.gitignore @@ -0,0 +1,3 @@ +*.syms +pie.lds +pie.lds.S diff --git a/pie/Makefile b/pie/Makefile new file mode 100644 index 000000000000..9afed70fa0c5 --- /dev/null +++ b/pie/Makefile @@ -0,0 +1,85 @@ +# +# linux/pie/Makefile +# +# Copyright 2013 Texas Instruments, Inc. +# Russ Dill <russ.dill@ti.com> +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# + +obj-y := pie.bin.o + +# Report unresolved symbol references +ldflags-y += --no-undefined +# Delete all temporary local symbols +ldflags-y += -X + +# Reset objcopy flags, ARM puts "-O binary" here +OBJCOPYFLAGS = + +# Reference gcc builtins for use in PIE with __pie_ +$(obj)/pie_rename.syms: $(KBUILD_LIBPIE) + @$(NM) $^ | awk '{if ($$3) print $$3,"__pie_"$$3}' > $@ + +# For weakening the links to the original gcc builtins +$(obj)/pie_weaken.syms: $(KBUILD_LIBPIE) + @$(NM) $^ | awk '{if ($$3) print "__pie_"$$3}' > $@ + +# For embedding address of the symbols copied from the PIE into the kernel +$(obj)/pie.syms: $(obj)/pie.elf + @$(NM) $^ | awk '{if ($$3 && $$2 == toupper($$2)) print $$3,"=","0x"$$1" + _binary_pie_pie_bin_start;"}' > $@ + +# Collect together the libpie objects +LDFLAGS_libpie_stage1.o += -r + +$(obj)/libpie_stage1.o: $(KBUILD_LIBPIE) + $(call if_changed,ld) + +# Rename the libpie gcc builtins with a __pie_ prefix +OBJCOPYFLAGS_libpie_stage2.o += --redefine-syms=$(obj)/pie_rename.syms +OBJCOPYFLAGS_libpie_stage2.o += --rename-section .text=.pie.text + +$(obj)/libpie_stage2.o: $(obj)/libpie_stage1.o + $(call if_changed,objcopy) + +# Generate a version of vmlinux.o with weakened and rename references to gcc +# builtins. +OBJCOPYFLAGS_pie_stage1.o += --weaken-symbols=$(obj)/pie_weaken.syms +OBJCOPYFLAGS_pie_stage1.o += --redefine-syms=$(obj)/pie_rename.syms + +$(obj)/pie_stage1.o: $(obj)/../vmlinux.o $(obj)/pie_rename.syms $(obj)/pie_weaken.syms + $(call if_changed,objcopy) + +# Drop in the PIE versions instead +LDFLAGS_pie_stage2.o += -r +# Allow the _GLOBAL_OFFSET_TABLE to redefine +LDFLAGS_pie_stage2.o += --defsym=_GLOBAL_OFFSET_TABLE_=_GLOBAL_OFFSET_TABLE_ + +$(obj)/pie_stage2.o: $(obj)/pie_stage1.o $(obj)/libpie_stage2.o + $(call if_changed,ld) + +# Drop everything but the pie sections +OBJCOPYFLAGS_pie_stage3.o += -j ".pie.*" + +$(obj)/pie_stage3.o: $(obj)/pie_stage2.o + $(call if_changed,objcopy) + +# Create the position independant executable +LDFLAGS_pie.elf += -T $(KBUILD_PIE_LDS) --pie --gc-sections + +$(obj)/pie.elf: $(obj)/pie_stage3.o $(KBUILD_PIE_LDS) + $(call if_changed,ld) + +# Create binary data for the kernel +OBJCOPYFLAGS_pie.bin += -O binary + +$(obj)/pie.bin: $(obj)/pie.elf $(obj)/pie.syms + $(call if_changed,objcopy) + +# Import the data into the kernel +OBJCOPYFLAGS_pie.bin.o += -B $(ARCH) -I binary -O $(OBJCOPY_OUTPUT_FORMAT) + +$(obj)/pie.bin.o: $(obj)/pie.bin + $(call if_changed,objcopy) |