From 672a303852353ba9299f6f50190fca8b3abe4c1d Mon Sep 17 00:00:00 2001 From: Yann Sionneau Date: Fri, 2 Oct 2020 16:24:55 +0200 Subject: kvx: add support for kvx arch to uClibc-ng MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds support for Kalray VLIW family (kvx) Kalray kv3 core is embedded in Kalray Coolidge SoC. This core which is the third of the KV family has the following features: 32/64 bits execution mode 6-issue VLIW architecture 64 x 64bits general purpose registers SIMD instructions little-endian In order to build a usable toolchain, build scripts are provided at the following address: https://github.com/kalray/build-scripts. Kalray uses FOSS which is available at https://github.com/kalray This includes Linux kernel, uClibc-ng, gcc, binutils, etc. Signed-off-by: Clément Léger Signed-off-by: Guillaume Thouvenin Signed-off-by: Laurent Thevenoux Signed-off-by: Marc Poulhies Signed-off-by: Marius Gligor Signed-off-by: Yann Sionneau --- ldso/ldso/kvx/dl-startup.h | 104 +++++++++++++++ ldso/ldso/kvx/dl-syscalls.h | 1 + ldso/ldso/kvx/dl-sysdep.h | 99 +++++++++++++++ ldso/ldso/kvx/dl-tlsdesc.S | 33 +++++ ldso/ldso/kvx/elfinterp.c | 302 ++++++++++++++++++++++++++++++++++++++++++++ ldso/ldso/kvx/resolve.S | 17 +++ 6 files changed, 556 insertions(+) create mode 100644 ldso/ldso/kvx/dl-startup.h create mode 100644 ldso/ldso/kvx/dl-syscalls.h create mode 100644 ldso/ldso/kvx/dl-sysdep.h create mode 100644 ldso/ldso/kvx/dl-tlsdesc.S create mode 100644 ldso/ldso/kvx/elfinterp.c create mode 100644 ldso/ldso/kvx/resolve.S (limited to 'ldso') diff --git a/ldso/ldso/kvx/dl-startup.h b/ldso/ldso/kvx/dl-startup.h new file mode 100644 index 000000000..9784c2345 --- /dev/null +++ b/ldso/ldso/kvx/dl-startup.h @@ -0,0 +1,104 @@ +/* + * Architecture specific code used by dl-startup.c + * Copyright (C) 2016 Waldemar Brodkorb + * Copyright (C) 2018 Kalray Inc. + * + * Ported from GNU libc + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Copyright (C) 1995-2016 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +/* This is the first bit of code, ever, executed in user space of a dynamically + * linked ELF. + * The kernel jumps on this with the following stack layout: + * argc argument counter (integer) + * argv[0] program name (pointer) + * argv[1..argc-1] program args (pointers) + * NULL + * env[0...N] environment variables (pointers) + * NULL + * auxvt[0...N] Auxiliary Vector Table elements (mixed types) + * + * We should call _dl_start($sp) (the argument should point to the previously + * described memory layout). + * + * Next we should skip N arguments (N == _dl_skip_args). + * Those correspond to the arguments which are consumed by the dynamic loader + * if it is called directly as a program, which is possible when + * __LDSO_STANDALONE_SUPPORT__ is defined. + * + * We eventually end up calling the main executable's _start (from ctr1.S). + * The address of this _start is returned by _dl_start (in $r0). + * + * We should call this with one argument (in $r0): the address of _dl_fini() + */ +__asm__("\ +.text \n\ +.globl _start \n\ +.type _start, %function \n\ +_start: \n\ + copyd $r0 = $sp \n\ + copyd $r18 = $sp \n\ + andd $sp = $sp, -32 \n\ + call _dl_start \n\ + ;; \n\ +.globl _dl_start_user \n\ +.type _dl_start_user, %function \n\ +_dl_start_user: \n\ + pcrel $r1 = @gotaddr() \n\ + copyd $r5 = $r0 \n\ + copyd $sp = $r18 \n\ + ;; \n\ + ld $r2 = @gotoff(_dl_skip_args)[$r1] \n\ + addd $r0 = $r1, @gotoff(_dl_fini) \n\ + ;; \n\ + lwz $r3 = 0[$sp] \n\ + ;; \n\ + sbfw $r4 = $r2, $r3 \n\ + addx8d $sp = $r2, $sp \n\ + ;; \n\ + sd 0[$sp] = $r4 \n\ + icall $r5 \n\ + ;; \n\ +"); + +/* Get a pointer to the argv array. On many platforms this can be just + * the address of the first argument, on other platforms we need to + * do something a little more subtle here. */ +#define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long*)ARGS)+1) + +/* Handle relocation of the symbols in the dynamic loader. */ +static __always_inline +void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, ElfW(Addr) *reloc_addr, + ElfW(Addr) symbol_addr, ElfW(Addr) load_addr, ElfW(Sym) *sym) +{ + switch (ELF_R_TYPE(rpnt->r_info)) { + case R_KVX_NONE: + break; + case R_KVX_JMP_SLOT: + *reloc_addr = symbol_addr + rpnt->r_addend; + break; + case R_KVX_RELATIVE: + *reloc_addr = load_addr + rpnt->r_addend; + break; + default: + _dl_exit(1); + } +} diff --git a/ldso/ldso/kvx/dl-syscalls.h b/ldso/ldso/kvx/dl-syscalls.h new file mode 100644 index 000000000..f40c4fd31 --- /dev/null +++ b/ldso/ldso/kvx/dl-syscalls.h @@ -0,0 +1 @@ +/* stub for arch-specific syscall issues */ diff --git a/ldso/ldso/kvx/dl-sysdep.h b/ldso/ldso/kvx/dl-sysdep.h new file mode 100644 index 000000000..9bb20ca8e --- /dev/null +++ b/ldso/ldso/kvx/dl-sysdep.h @@ -0,0 +1,99 @@ +/* + * Various assembly language/system dependent hacks that are required + * so that we can minimize the amount of platform specific code. + * Copyright (C) 2000-2004 by Erik Andersen + * Copyright (C) 2017-2018 by Waldemar Brodkorb + * Copyright (C) 2018 Kalray Inc. + + * Ported from GNU C Library + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Copyright (C) 1995-2017 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* Defines that this system uses RELOCA. */ +#define ELF_USES_RELOCA + +#include +#include + +/* Initialization sequence for the GOT. */ +#define INIT_GOT(GOT_BASE,MODULE) \ +{ \ + GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \ + GOT_BASE[1] = (unsigned long) MODULE; \ +} + +/* Here we define the magic numbers that this dynamic loader should accept */ +#define MAGIC1 EM_KVX +#undef MAGIC2 + +/* Used for error messages */ +#define ELF_TARGET "kvx" + +#define ARCH_NEEDS_BOOTSTRAP_RELOCS + +struct elf_resolve; +unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); + +#define elf_machine_type_class(type) \ + ((((type) == R_KVX_JMP_SLOT || (type) == R_KVX_64_DTPMOD || \ + (type) == R_KVX_64_DTPOFF \ + || (type) == R_KVX_64_TPOFF) \ + * ELF_RTYPE_CLASS_PLT) \ + | (((type) == R_KVX_COPY) * ELF_RTYPE_CLASS_COPY)) + +/* Return the link-time address of _DYNAMIC. Conveniently, this is the + first element of the GOT. */ +extern const ElfW(Addr) _GLOBAL_OFFSET_TABLE_[] attribute_hidden; +static __always_inline ElfW(Addr) __attribute__ ((unused)) +elf_machine_dynamic (void) +{ + unsigned long *ptr; + __asm__("\n" + "pcrel %0 = @gotaddr()\n" + ";;\n" : "=r"(ptr) :: ); + return *ptr; +} + +/* Return the run-time load address of the shared object. */ + +static __always_inline ElfW(Addr) __attribute__ ((unused)) +elf_machine_load_address (void) +{ + /* To figure out the load address we use the definition that for any symbol: + dynamic_addr(symbol) = static_addr(symbol) + load_addr + + _DYNAMIC sysmbol is used here as its link-time address stored in + the special unrelocated first GOT entry. */ + + extern ElfW(Dyn) _DYNAMIC[] attribute_hidden; + return (ElfW(Addr)) &_DYNAMIC - elf_machine_dynamic (); +} + +static __always_inline void +elf_machine_relative(Elf64_Addr load_off, const Elf64_Addr rel_addr, + Elf64_Word relative_count) +{ + Elf64_Rela *rpnt = (Elf64_Rela*)rel_addr; + --rpnt; + do { + Elf64_Addr *const reloc_addr = (Elf64_Addr*)(load_off + (++rpnt)->r_offset); + + *reloc_addr = load_off + rpnt->r_addend; + } while (--relative_count); +} diff --git a/ldso/ldso/kvx/dl-tlsdesc.S b/ldso/ldso/kvx/dl-tlsdesc.S new file mode 100644 index 000000000..d0a55b985 --- /dev/null +++ b/ldso/ldso/kvx/dl-tlsdesc.S @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2018 Kalray Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#if defined __UCLIBC_HAS_TLS__ +#error NOT IMPLEMENTED: THIS IS A SKELETON + .text + + .hidden _dl_tlsdesc_return + .global _dl_tlsdesc_return + .type _dl_tlsdesc_return,%function + .align 2 +_dl_tlsdesc_return: + errop + ;; +.size _dl_tlsdesc_return, .-_dl_tlsdesc_return + +#ifdef SHARED + + .hidden _dl_tlsdesc_dynamic + .global _dl_tlsdesc_dynamic + .type _dl_tlsdesc_dynamic,%function + cfi_startproc + .align 2 +_dl_tlsdesc_dynamic: + errop + ;; + cfi_endproc + .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic + +#endif // SHARED +#endif // __UCLIBC_HAS_TLS__ diff --git a/ldso/ldso/kvx/elfinterp.c b/ldso/ldso/kvx/elfinterp.c new file mode 100644 index 000000000..9efcf83ff --- /dev/null +++ b/ldso/ldso/kvx/elfinterp.c @@ -0,0 +1,302 @@ +/* KVX ELF shared library loader suppport + * + * Copyright (C) 2001-2004 Erik Andersen + * Copyright (C) 2016-2017 Waldemar Brodkorb + * Copyright (C) 2018 Kalray Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the above contributors may not be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Program to load an ELF binary on a linux system, and run it. + References to symbols in sharable libraries can be resolved by either + an ELF sharable library or a linux style of shared library. */ + +#include "ldso.h" + +#if defined(USE_TLS) && USE_TLS +#include "dl-tls.h" +#include "tlsdeschtab.h" +#endif + +extern int _dl_linux_resolve(void); + +/* Uncomment when some relocs will be handled lazily */ +#if 0 +unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) +{ + ELF_RELOC *this_reloc; + char *strtab; + ElfW(Sym) *symtab; + int symtab_index; + char *rel_addr; + char *new_addr; + char **got_addr; + ElfW(Addr) instr_addr; + char *symname; + + rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL]; + this_reloc = (ELF_RELOC *)(rel_addr + reloc_entry); + symtab_index = ELF_R_SYM(this_reloc->r_info); + + symtab = (ElfW(Sym) *)tpnt->dynamic_info[DT_SYMTAB]; + strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; + symname = strtab + symtab[symtab_index].st_name; + + /* Address of jump instruction to fix up */ + instr_addr = (this_reloc->r_offset + tpnt->loadaddr); + got_addr = (char **)instr_addr; + + /* Get the address of the GOT entry */ + new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL); + if (unlikely(!new_addr)) { + _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname); + _dl_exit(1); + } +#if defined (__SUPPORT_LD_DEBUG__) + if (_dl_debug_bindings) { + _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname); + if (_dl_debug_detail) _dl_dprintf(_dl_debug_file, + "\tpatched %x ==> %x @ %x", *got_addr, new_addr, got_addr); + } + if (!_dl_debug_nofixups) { + *got_addr = new_addr; + } +#else + *got_addr = new_addr; +#endif + return (unsigned long)new_addr; +} +#endif + +static int +_dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope, + unsigned long rel_addr, unsigned long rel_size, + int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)) +{ + unsigned int i; + char *strtab; + ElfW(Sym) *symtab; + ELF_RELOC *rpnt; + int symtab_index; + + /* Parse the relocation information */ + rpnt = (ELF_RELOC *)rel_addr; + rel_size = rel_size / sizeof(ELF_RELOC); + + symtab = (ElfW(Sym) *)tpnt->dynamic_info[DT_SYMTAB]; + strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; + + for (i = 0; i < rel_size; i++, rpnt++) { + int res; + + symtab_index = ELF_R_SYM(rpnt->r_info); + + debug_sym(symtab, strtab, symtab_index); + debug_reloc(symtab, strtab, rpnt); + + res = reloc_fnc(tpnt, scope, rpnt, symtab, strtab); + + if (res==0) + continue; + + _dl_dprintf(2, "\n%s: ", _dl_progname); + + if (symtab_index) + _dl_dprintf(2, "symbol '%s': ", + strtab + symtab[symtab_index].st_name); + + if (unlikely(res < 0)) { + int reloc_type = ELF_R_TYPE(rpnt->r_info); + _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type); + _dl_exit(-res); + } else if (unlikely(res > 0)) { + _dl_dprintf(2, "can't resolve symbol\n"); + return res; + } + } + + return 0; +} + +static int +_dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab) +{ + int reloc_type; + int symtab_index; + char *symname; +#if defined USE_TLS && USE_TLS + struct elf_resolve *tls_tpnt = NULL; +#endif + struct symbol_ref sym_ref; + ElfW(Addr) *reloc_addr; + ElfW(Addr) symbol_addr; +#if defined (__SUPPORT_LD_DEBUG__) + ElfW(Addr) old_val; +#endif + + reloc_addr = (ElfW(Addr)*)(tpnt->loadaddr + (unsigned long)rpnt->r_offset); + reloc_type = ELF_R_TYPE(rpnt->r_info); + symtab_index = ELF_R_SYM(rpnt->r_info); + sym_ref.sym = &symtab[symtab_index]; + sym_ref.tpnt = NULL; + symbol_addr = 0; + symname = strtab + sym_ref.sym->st_name; + + if (symtab_index) { + symbol_addr = (ElfW(Addr))_dl_find_hash(symname, scope, tpnt, + elf_machine_type_class(reloc_type), &sym_ref); + + /* + * We want to allow undefined references to weak symbols - this might + * have been intentional. We should not be linking local symbols + * here, so all bases should be covered. + */ + if (unlikely (!symbol_addr && + (ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS) && + (ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK))) { + return 1; + } + if (_dl_trace_prelink) { + _dl_debug_lookup (symname, tpnt, &symtab[symtab_index], + &sym_ref, elf_machine_type_class(reloc_type)); + } +#if defined USE_TLS && USE_TLS + tls_tpnt = sym_ref.tpnt; +#endif + } else { + /* + * Relocs against STN_UNDEF are usually treated as using a + * symbol value of zero, and using the module containing the + * reloc itself. + */ + symbol_addr = sym_ref.sym->st_value; +#if defined USE_TLS && USE_TLS + tls_tpnt = tpnt; +#endif + } + +#if defined (__SUPPORT_LD_DEBUG__) + old_val = *reloc_addr; +#endif + + switch (reloc_type) { + case R_KVX_NONE: + break; + case R_KVX_GLOB_DAT: + case R_KVX_64: + case R_KVX_JMP_SLOT: + *reloc_addr = symbol_addr + rpnt->r_addend; + break; + case R_KVX_COPY: + if (symbol_addr) { + _dl_memcpy((char *)reloc_addr, (char *)symbol_addr, + sym_ref.sym->st_size); + } + break; + +#if defined USE_TLS && USE_TLS + case R_KVX_64_TPOFF: + CHECK_STATIC_TLS ((struct link_map *) tls_tpnt); + *reloc_addr = tls_tpnt->l_tls_offset + symbol_addr + rpnt->r_addend - TLS_TCB_SIZE; + break; + case R_KVX_64_DTPMOD: + *reloc_addr = tls_tpnt->l_tls_modid; + break; + case R_KVX_64_DTPOFF: + *reloc_addr = symbol_addr; + break; +#endif + default: + return -1; /*call _dl_exit(1) */ + } + +#if defined (__SUPPORT_LD_DEBUG__) + if (_dl_debug_reloc && _dl_debug_detail) { + _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", + old_val, *reloc_addr, reloc_addr); + } +#endif + + return 0; +} + +/* uncomment when PLT relocs will be handled lazily */ +#if 0 +static int +_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab) +{ + int reloc_type; + ElfW(Addr) *reloc_addr; +#if defined (__SUPPORT_LD_DEBUG__) + ElfW(Addr) old_val; +#endif + + (void)scope; + (void)strtab; + + reloc_addr = (ElfW(Addr)*)(tpnt->loadaddr + rpnt->r_offset); + reloc_type = ELF_R_TYPE(rpnt->r_info); + +#if defined (__SUPPORT_LD_DEBUG__) + old_val = *reloc_addr; +#endif + + switch (reloc_type) { + case R_KVX_NONE: + break; + case R_KVX_JMP_SLOT64: + *reloc_addr += tpnt->loadaddr; + break; +#if defined USE_TLS && USE_TLS +#error Not even close to be ready +#endif + default: + return -1; /*call _dl_exit(1) */ + } + +#if defined (__SUPPORT_LD_DEBUG__) + if (_dl_debug_reloc && _dl_debug_detail) { + _dl_dprintf(_dl_debug_file, "\tpatched_lazy: %x ==> %x @ %x\n", + old_val, *reloc_addr, reloc_addr); + } +#endif + + return 0; +} +#endif + +void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, + unsigned long rel_addr, unsigned long rel_size) +{ + (void)_dl_parse(rpnt->dyn, &_dl_loaded_modules->symbol_scope, rel_addr, rel_size, _dl_do_reloc); +} + +int _dl_parse_relocation_information(struct dyn_elf *rpnt, + struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size) +{ + return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc); +} diff --git a/ldso/ldso/kvx/resolve.S b/ldso/ldso/kvx/resolve.S new file mode 100644 index 000000000..6e7c3143c --- /dev/null +++ b/ldso/ldso/kvx/resolve.S @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2018 Kalray Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#warning NOT IMPLEMENTED: THIS IS A SKELETON + + .text + .globl _dl_linux_resolve + .type _dl_linux_resolve, %function + .align 2 + +_dl_linux_resolve: + errop + ;; + +.size _dl_linux_resolve, .-_dl_linux_resolve -- cgit v1.2.3