summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkettenis <kettenis@openbsd.org>2014-12-27 13:17:51 +0000
committerkettenis <kettenis@openbsd.org>2014-12-27 13:17:51 +0000
commit2f7dfe5d206aa9341f2242ffd4e9f8373d3f8f5f (patch)
treed061aa02345f3b505e7e88211afb53483579091c
parentMake ld.so process only R_ALPHA_RELATIVE relocations during early GOT (diff)
downloadwireguard-openbsd-2f7dfe5d206aa9341f2242ffd4e9f8373d3f8f5f.tar.xz
wireguard-openbsd-2f7dfe5d206aa9341f2242ffd4e9f8373d3f8f5f.zip
Static PIE support for alpha.
This adds alpha-specific first-pass GOT relocation code to boot.h. The assembly code is pure magic. The numeric register names don't make it easier to understand (or compare with the equivalent ld.so code). Unfortunately the assembler only understands a few symbolic register names. Renames the crt0.o entry point to __start. Our compiler was already using __start and the linker will soon follow. ok kurt@
-rw-r--r--lib/csu/alpha/md_init.h50
-rw-r--r--lib/csu/boot.h38
2 files changed, 80 insertions, 8 deletions
diff --git a/lib/csu/alpha/md_init.h b/lib/csu/alpha/md_init.h
index 04a726860ab..9526e212566 100644
--- a/lib/csu/alpha/md_init.h
+++ b/lib/csu/alpha/md_init.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: md_init.h,v 1.2 2013/12/03 06:21:40 guenther Exp $ */
+/* $OpenBSD: md_init.h,v 1.3 2014/12/27 13:17:52 kettenis Exp $ */
/*-
* Copyright (c) 2001 Ross Harvey
* All rights reserved.
@@ -62,14 +62,52 @@
" ret \n" \
" .previous")
-/* XXX this should not be necessary: ld should use __start */
+
#define MD_CRT0_START \
__asm ( \
- ".globl _start \n" \
- ".type _start@function \n" \
- "_start = __start")
+ " .globl __start \n" \
+ " .type __start@function \n" \
+ "__start = ___start")
+
+#define MD_RCRT0_START \
+ __asm ( \
+ " .globl __start \n" \
+ " .type __start@function \n" \
+ "__start: \n" \
+ " .set noreorder \n" \
+ " br $27, L1 \n" \
+ "L1: \n" \
+ " ldgp $gp, 0($27) \n" \
+ " mov $16, $9 \n" \
+ " br $11, L2 \n" \
+ "L2: ldiq $12, L2 \n" \
+ " subq $11, $12, $11 \n" \
+ " mov $11, $17 \n" \
+ " lda $6, _DYNAMIC \n" \
+ " addq $11, $6, $16 \n" \
+ " bsr $26, _reloc_alpha_got \n" \
+ " lda $sp, -80($sp) \n" \
+ " mov $9, $16 \n" \
+ " lda $11, 0($sp) \n" \
+ " mov $11, $17 \n" \
+ " mov 0, $18 \n" \
+ " jsr $26, _dl_boot_bind \n" \
+ " ldgp $gp, 0($26) \n" \
+ " mov $9, $16 \n" \
+ " mov 0, $17 \n" \
+ " jsr $26, ___start \n" \
+ ".globl _dl_exit \n" \
+ ".type _dl_exit@function \n" \
+ "_dl_exit: \n" \
+ " lda $0, 1 \n" \
+ " callsys \n" \
+ " ret \n" \
+ ".globl _dl_printf \n" \
+ ".type _dl_printf@function \n" \
+ "_dl_printf: \n" \
+ " ret")
-#define MD_START __start
+#define MD_START ___start
#define MD_START_ARGS char **sp, void (*cleanup)(void)
#define MD_START_SETUP \
char **argv, **envp; \
diff --git a/lib/csu/boot.h b/lib/csu/boot.h
index f7c8c5f9f21..4120d54adb4 100644
--- a/lib/csu/boot.h
+++ b/lib/csu/boot.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: boot.h,v 1.7 2014/12/25 21:38:45 kurt Exp $ */
+/* $OpenBSD: boot.h,v 1.8 2014/12/27 13:17:51 kettenis Exp $ */
/*
* Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -54,6 +54,7 @@
#include "../../lib/csu/os-note-elf.h"
#ifdef RCRT0
+
/*
* Local decls.
*/
@@ -282,7 +283,7 @@ _dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynamicp)
else
pagesize = 4096;
-#if defined(__sparc64__)
+#if defined(__alpha__) || defined(__sparc64__)
start = ELF_TRUNC((Elf_Addr)__plt_start, pagesize);
size = ELF_ROUND((Elf_Addr)__plt_end - start, pagesize);
mprotect((void *)start, size, PROT_READ);
@@ -292,4 +293,37 @@ _dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynamicp)
size = ELF_ROUND((Elf_Addr)__got_end - start, pagesize);
mprotect((void *)start, size, GOT_PERMS);
}
+
+#ifdef __alpha__
+
+void _reloc_alpha_got(Elf_Dyn *dynp, Elf_Addr relocbase);
+
+void
+_reloc_alpha_got(Elf_Dyn *dynp, Elf_Addr relocbase)
+{
+ const Elf_RelA *rela = 0, *relalim;
+ Elf_Addr relasz = 0;
+ Elf_Addr *where;
+
+ for (; dynp->d_tag != DT_NULL; dynp++) {
+ switch (dynp->d_tag) {
+ case DT_RELA:
+ rela = (const Elf_RelA *)(relocbase + dynp->d_un.d_ptr);
+ break;
+ case DT_RELASZ:
+ relasz = dynp->d_un.d_val;
+ break;
+ }
+ }
+ relalim = (const Elf_RelA *)((caddr_t)rela + relasz);
+ for (; rela < relalim; rela++) {
+ if (ELF64_R_TYPE(rela->r_info) != RELOC_RELATIVE)
+ continue;
+ where = (Elf_Addr *)(relocbase + rela->r_offset);
+ *where += (Elf_Addr)relocbase;
+ }
+}
+
+#endif
+
#endif /* RCRT0 */