From 6068820bf3827a2560eec2c1bd46e2ccab08a5c6 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 1 Jun 2015 14:16:18 -0600 Subject: [PATCH] Add support uClibc++ excpetions. This involves additional handling for relative relation types, additional support for unwinding, as well as additional changes. The culmination of a big effort fromo Leo Aloe3132 --- arch/arm/src/armv7-m/Kconfig | 7 ++ arch/arm/src/armv7-m/up_elf.c | 33 ++++++ binfmt/libelf/Kconfig | 10 ++ binfmt/libelf/libelf_load.c | 15 +++ configs/stm32f4discovery/scripts/gnu-elf.ld | 10 ++ include/nuttx/binfmt/elf.h | 19 ++++ libxx/Makefile | 3 + libxx/libxx__gnu_unwind_find_exidx.cxx | 106 ++++++++++++++++++++ libxx/libxx__gnu_unwind_find_exidx.hxx | 80 +++++++++++++++ 9 files changed, 283 insertions(+) create mode 100644 libxx/libxx__gnu_unwind_find_exidx.cxx create mode 100644 libxx/libxx__gnu_unwind_find_exidx.hxx diff --git a/arch/arm/src/armv7-m/Kconfig b/arch/arm/src/armv7-m/Kconfig index b8c3cb8179..0e2e6b6866 100644 --- a/arch/arm/src/armv7-m/Kconfig +++ b/arch/arm/src/armv7-m/Kconfig @@ -106,6 +106,13 @@ config ARMV7M_OABI_TOOLCHAIN Most of the older buildroot toolchains are OABI and are named arm-nuttx-elf- vs. arm-nuttx-eabi- +config ARMV7M_TARGET2_PREL + bool "R_ARM_TARGET2 is PC relative" + default n + depends on ELF + ---help--- + Perform a PC relative relocation for relocation type R_ARM_TARGET2 + config ARMV7M_HAVE_STACKCHECK bool default n diff --git a/arch/arm/src/armv7-m/up_elf.c b/arch/arm/src/armv7-m/up_elf.c index c1ea4e4941..4c5155f665 100644 --- a/arch/arm/src/armv7-m/up_elf.c +++ b/arch/arm/src/armv7-m/up_elf.c @@ -48,6 +48,8 @@ #include #include +#ifdef CONFIG_ELF + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -60,6 +62,14 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_UCLIBCXX_EXCEPTION +extern void init_unwind_exidx(Elf32_Addr start, Elf32_Addr end); +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -204,6 +214,18 @@ int up_relocate(FAR const Elf32_Rel *rel, FAR const Elf32_Sym *sym, } break; +#ifdef CONFIG_ARMV7M_TARGET2_PREL + case R_ARM_TARGET2: /* TARGET2 is a platform-specific relocation: gcc-arm-none-eabi + * performs a self relocation */ + { + bvdbg("Performing TARGET2 link at addr=%08lx [%08lx] to sym=%p st_value=%08lx\n", + (long)addr, (long)(*(uint32_t*)addr), sym, (long)sym->st_value); + + *(uint32_t*)addr += sym->st_value - addr; + } + break; +#endif + case R_ARM_THM_CALL: case R_ARM_THM_JUMP24: { @@ -464,3 +486,14 @@ int up_relocateadd(FAR const Elf32_Rela *rel, FAR const Elf32_Sym *sym, bdbg("RELA relocation not supported\n"); return -ENOSYS; } + +#ifdef CONFIG_UCLIBCXX_EXCEPTION +int up_init_exidx(Elf32_Addr address, Elf32_Word size) +{ + init_unwind_exidx(address, size); + + return OK; +} +#endif + +#endif /* CONFIG_ELF */ diff --git a/binfmt/libelf/Kconfig b/binfmt/libelf/Kconfig index e63fd53822..0a3f9976fd 100644 --- a/binfmt/libelf/Kconfig +++ b/binfmt/libelf/Kconfig @@ -38,3 +38,13 @@ config ELF_DUMPBUFFER depends on DEBUG && DEBUG_VERBOSE ---help--- Dump various ELF buffers for debug purposes + +config ELF_EXIDX_SECTNAME + string "ELF Section Name for Exception Index" + default ".ARM.exidx" + depends on UCLIBCXX_EXCEPTION + ---help--- + Set the name string for the exception index section on the ELF modules to + be loaded by the ELF binary loader. + + This is needed to support exception handling on loadable ELF modules. diff --git a/binfmt/libelf/libelf_load.c b/binfmt/libelf/libelf_load.c index 2303e53ad6..c81be5c196 100644 --- a/binfmt/libelf/libelf_load.c +++ b/binfmt/libelf/libelf_load.c @@ -245,6 +245,9 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) int elf_load(FAR struct elf_loadinfo_s *loadinfo) { size_t heapsize; +#ifdef CONFIG_UCLIBCXX_EXCEPTION + int exidx; +#endif int ret; bvdbg("loadinfo: %p\n", loadinfo); @@ -328,6 +331,18 @@ int elf_load(FAR struct elf_loadinfo_s *loadinfo) } #endif +#ifdef CONFIG_UCLIBCXX_EXCEPTION + exidx = elf_findsection(loadinfo, CONFIG_ELF_EXIDX_SECTNAME); + if (exidx < 0) + { + bvdbg("elf_findsection: Exception Index section not found: %d\n", exidx); + } + else + { + up_init_exidx(loadinfo->shdr[exidx].sh_addr, loadinfo->shdr[exidx].sh_size); + } +#endif + #ifdef CONFIG_ARCH_ADDRENV /* Restore the original address environment */ diff --git a/configs/stm32f4discovery/scripts/gnu-elf.ld b/configs/stm32f4discovery/scripts/gnu-elf.ld index 1f29f02f5b..2e9357ec49 100644 --- a/configs/stm32f4discovery/scripts/gnu-elf.ld +++ b/configs/stm32f4discovery/scripts/gnu-elf.ld @@ -56,6 +56,16 @@ SECTIONS _etext = . ; } + .ARM.extab : + { + *(.ARM.extab*) + } + + .ARM.exidx : + { + *(.ARM.exidx*) + } + .rodata : { _srodata = . ; diff --git a/include/nuttx/binfmt/elf.h b/include/nuttx/binfmt/elf.h index 3d5e9e2ad3..ed42499356 100644 --- a/include/nuttx/binfmt/elf.h +++ b/include/nuttx/binfmt/elf.h @@ -320,6 +320,25 @@ int up_relocate(FAR const Elf32_Rel *rel, FAR const Elf32_Sym *sym, int up_relocateadd(FAR const Elf32_Rela *rel, FAR const Elf32_Sym *sym, uintptr_t addr); +#ifdef CONFIG_UCLIBCXX_EXCEPTION +/**************************************************************************** + * Name: up_init_exidx + * + * Description: + * Load the boundaries of the Exception Index ELF section in order to + * support exception handling for loaded ELF modules. + * + * Input Parameters: + * address - The ELF section address for the Exception Index + * size - The size of the ELF section. + * + * Returned Value: + * Always returns Zero (OK). + * + ****************************************************************************/ +int up_init_exidx(Elf32_Addr address, Elf32_Word size); +#endif + /**************************************************************************** * Name: up_coherent_dcache * diff --git a/libxx/Makefile b/libxx/Makefile index 261e40de8c..40292aa0bc 100644 --- a/libxx/Makefile +++ b/libxx/Makefile @@ -41,6 +41,9 @@ ASRCS = CSRCS = CXXSRCS = libxx_cxapurevirtual.cxx libxx_eabi_atexit.cxx libxx_cxa_atexit.cxx +ifeq ($(CONFIG_UCLIBCXX_EXCEPTION),y) +CXXSRCS += libxx__gnu_unwind_find_exidx.cxx +endif # Some of the libxx/ files are not need if uClibc++ is installed because # uClibx++ replaces them diff --git a/libxx/libxx__gnu_unwind_find_exidx.cxx b/libxx/libxx__gnu_unwind_find_exidx.cxx new file mode 100644 index 0000000000..b5ddfe31a3 --- /dev/null +++ b/libxx/libxx__gnu_unwind_find_exidx.cxx @@ -0,0 +1,106 @@ +//*************************************************************************** +// libxx/libxx__gnu_unwind_find_exidx.cxx +// +// Copyright (C) 2015 Gregory Nutt. All rights reserved. +// Author: Gregory Nutt +// +// 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. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// 3. Neither the name NuttX nor the names of its contributors may be +// used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 +// COPYRIGHT OWNER OR 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. +// +//*************************************************************************** + +//*************************************************************************** +// Included Files +//*************************************************************************** + +#include "libxx__gnu_unwind_find_exidx.hxx" + +//*************************************************************************** +// Pre-processor Definitions +//*************************************************************************** + +//*************************************************************************** +// Private Data +//*************************************************************************** + +//*************************************************************************** +// Operators +//*************************************************************************** + +//*************************************************************************** +// Name: __gnu_Unwind_Find_exidx +// +// Description: +// This function is called (if exists) by the gcc generated unwind +// run-time in order to retrieve an alternative .ARM.exidx Exception +// index section. +// This is the case for an ELF module loaded by the elf binary loader. +// It is needed to support exception handling for loadable ELF modules. +// +// NOTES: +// +// 1. The section to be searched is chosen by the address of the calling +// site: if we are in a runtime loaded ELF, the code will be executed +// in ram ( > 0x20000000 ) otherwise we will be executing code from +// flash (0x08000000) (running nuttx from ram will break this logic) +// +// 2. __exidx_start and __exidx_end refers to main nuttx elf image and +// are defined in its linker script. +// +// 2. __exidx_start_elf and __exidx_end_elf refers to the elf module +// loaded by the elf binary loader, and are initialized at run-time. +// +// 3. TODO: if nuttx itself is running from ram, this logic will not work +// +// 4. TODO: in order to support multiple elf modules running at the same +// time, this error logic needs to be extended to store multiple +// start/end ranges that refers to the loaded binaries. +// +//*************************************************************************** + +extern "C" +{ + void init_unwind_exidx(Elf32_Addr start, Elf32_Word size) + { + __exidx_start_elf = (__EIT_entry *) start; + __exidx_end_elf = __exidx_start_elf + size; + } + + _Unwind_Ptr __gnu_Unwind_Find_exidx (_Unwind_Ptr return_address, int *nrecp) + { + if (return_address < 0x20000000) + { + *nrecp = &__exidx_end - &__exidx_start; + return (_Unwind_Ptr) &__exidx_start; + } + else + { + *nrecp = (__exidx_end_elf - __exidx_start_elf) / sizeof(__EIT_entry); + return (_Unwind_Ptr) __exidx_start_elf; + } + } +} diff --git a/libxx/libxx__gnu_unwind_find_exidx.hxx b/libxx/libxx__gnu_unwind_find_exidx.hxx new file mode 100644 index 0000000000..0925d76e90 --- /dev/null +++ b/libxx/libxx__gnu_unwind_find_exidx.hxx @@ -0,0 +1,80 @@ +//*************************************************************************** +// lib/libxx__gnu_unwind_find_exidx.hxx +// +// Copyright (C) 2015 Gregory Nutt. All rights reserved. +// Author: Gregory Nutt +// +// 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. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// 3. Neither the name NuttX nor the names of its contributors may be +// used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 +// COPYRIGHT OWNER OR 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. +// +//*************************************************************************** + +#ifndef __LIBXX_LIBXX__GNU_UNWIND_FIND_EXIDX_HXX +#define __LIBXX_LIBXX__GNU_UNWIND_FIND_EXIDX_HXX + +extern "C" +{ +//*************************************************************************** +// Included Files +//*************************************************************************** + +#include +#include + +//*************************************************************************** +// Pre-processor Definitions +//*************************************************************************** + +//*************************************************************************** +// Public Types +//***************************************************************************/ + +typedef struct __EIT_entry +{ + _uw fnoffset; + _uw content; +} __EIT_entry; + +//*************************************************************************** +// Public Variables +//*************************************************************************** + +extern __EIT_entry __exidx_start; +extern __EIT_entry __exidx_end; + +__EIT_entry *__exidx_start_elf; +__EIT_entry *__exidx_end_elf; + +//*************************************************************************** +// Public Function Prototypes +//*************************************************************************** + + _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr return_address, int *nrecp); + +} // extern "C" + +#endif // __LIBXX__GNU_UNWIND_FIND_EXIDX_HXX