This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 8d08885d0f930e30f47c4af25876e67ea39ba963 Author: Marco Casaroli <[email protected]> AuthorDate: Sun Aug 2 21:26:48 2026 +0200 tools/nxflat: Import the NXFLAT thunk generator. An NXFLAT module reaches the base firmware through a "thunk" file: one assembly stub per imported function, generated by mknxflat. That tool has always lived outside this repository, in the NuttX buildroot NXFLAT toolchain, so building an NXFLAT module needs a separate checkout and a separate build of a tool that links against libbfd. libbfd is why it stayed out. It is GPL, which an Apache project cannot depend on, and it is awkward to obtain besides -- a stock binutils install often ships libbfd without the libiberty it needs to link. But the dependency was never deep. mknxflat used libbfd for eight calls, all of them opening the file and walking the symbol table; it never relocates or rewrites anything. That is replaced here by reading the ELF symbol table directly, which removes the dependency outright and costs about a hundred lines. The emitted text is unchanged. The format strings live in the .def files, which are carried here byte-for-byte from upstream, and the selection rule for what becomes a thunk is the upstream one: everything undefined that is not explicitly an object. Symbol typing cannot be trusted for this -- imported functions are routinely emitted as STT_NOTYPE rather than STT_FUNC, while a weakly defined object does appear as an undefined object -- so the test is on what a symbol is not. Upstream chose the instruction set at compile time through an "arch" symlink pointing at either arm/ or thumb2/. A symlink cannot be carried in the repository, and one host binary has to serve boards of both flavours, since lpc31xx is ARM while lpc17xx, tiva, stm32f1 and rp23xx are Thumb-2. That choice becomes a runtime "-a" option. The "-f" option, which read further command line arguments from a file, is dropped; nothing in the tree used it. This commit changes no output. Against the upstream tool, for both architectures, with and without -w, over modules exercising the plain, weak and non-returning thunk paths, the generated thunk files are byte-identical. Assisted-by: Claude Opus 5 (1M context) <[email protected]> Signed-off-by: Marco Casaroli <[email protected]> --- tools/.gitignore | 1 + tools/Makefile.host | 19 +- tools/nxflat/dyncall_skeleton_arm.def | 251 ++++++++++ tools/nxflat/dyncall_skeleton_thumb2.def | 222 +++++++++ tools/nxflat/mknxflat.c | 770 +++++++++++++++++++++++++++++++ tools/nxflat/nxflat_thunk.h | 79 ++++ tools/nxflat/thunk_arm.c | 62 +++ tools/nxflat/thunk_thumb2.c | 62 +++ 8 files changed, 1464 insertions(+), 2 deletions(-) diff --git a/tools/.gitignore b/tools/.gitignore index 957b27157d5..a30ce43ca8d 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -7,6 +7,7 @@ /gencromfs /initialconfig /mkconfig +/mknxflat /mkdeps /cnvwindeps /logparser diff --git a/tools/Makefile.host b/tools/Makefile.host index 3a2926cd659..c378a8d7dae 100644 --- a/tools/Makefile.host +++ b/tools/Makefile.host @@ -39,14 +39,15 @@ all: b16$(HOSTEXEEXT) bdf-converter$(HOSTEXEEXT) cmpconfig$(HOSTEXEEXT) \ initialconfig$(HOSTEXEEXT) gencromfs$(HOSTEXEEXT) \ convert-comments$(HOSTEXEEXT) lowhex$(HOSTEXEEXT) \ detab$(HOSTEXEEXT) rmcr$(HOSTEXEEXT) incdir$(HOSTEXEEXT) \ - jlink-nuttx$(HOSTDYNEXT) + mknxflat$(HOSTEXEEXT) jlink-nuttx$(HOSTDYNEXT) default: mkconfig$(HOSTEXEEXT) mksyscall$(HOSTEXEEXT) mkdeps$(HOSTEXEEXT) \ cnvwindeps$(HOSTEXEEXT) incdir$(HOSTEXEEXT) ifdef HOSTEXEEXT .PHONY: b16 bdf-converter cmpconfig clean configure kconfig2html mkconfig \ mkdeps mksymtab mksyscall mkversion mkpasswd cnvwindeps nxstyle \ - initialconfig gencromfs convert-comments lowhex detab rmcr incdir + initialconfig gencromfs convert-comments lowhex detab rmcr incdir \ + mknxflat endif ifdef HOSTDYNEXT .PHONY: jlink-nuttx @@ -134,6 +135,18 @@ ifdef HOSTEXEEXT mksymtab: mksymtab$(HOSTEXEEXT) endif +# mknxflat - Generate the thunk file for an NXFLAT module + +MKNXFLAT_SRCS = nxflat/mknxflat.c nxflat/thunk_arm.c nxflat/thunk_thumb2.c + +mknxflat$(HOSTEXEEXT): $(MKNXFLAT_SRCS) + $(Q) $(HOSTCC) $(HOSTCFLAGS) -Inxflat -o mknxflat$(HOSTEXEEXT) \ + $(MKNXFLAT_SRCS) + +ifdef HOSTEXEEXT +mknxflat: mknxflat$(HOSTEXEEXT) +endif + # bdf-converter - Converts a BDF font to the NuttX font format bdf-converter$(HOSTEXEEXT): bdf-converter.c @@ -270,6 +283,8 @@ clean: $(call DELFILE, Make.dep) $(call DELFILE, mkconfig) $(call DELFILE, mkconfig.exe) + $(call DELFILE, mknxflat) + $(call DELFILE, mknxflat.exe) $(call DELFILE, mkdeps) $(call DELFILE, mkdeps.exe) $(call DELFILE, mksymtab) diff --git a/tools/nxflat/dyncall_skeleton_arm.def b/tools/nxflat/dyncall_skeleton_arm.def new file mode 100644 index 00000000000..0dd0951101f --- /dev/null +++ b/tools/nxflat/dyncall_skeleton_arm.def @@ -0,0 +1,251 @@ +/*********************************************************************** + * toolchain/nxflat/arm/dyncall_skeleton.def + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <[email protected]> + * + * 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. + * + ***********************************************************************/ + +/******************************************************************* + * File Prologue + *******************************************************************/ + +static const char file_prologue[] = + "/*******************************************************************\n" + " *\n" + " * This file contains the dynamic call logic that performs the thunk\n" + " * for outound calls from one module to another.\n" + " *\n" + " * ARM register quick reference:\n" + " *\n" + " * Name Number ARM Procedure Calling Standard Role\n" + " *\n" + " * a1 r0 argument 1/integer result/scratch register/argc\n" + " * a2 r1 argument 2/scratch register/argv\n" + " * a3 r2 argument 3/scratch register/envp\n" + " * a4 r3 argument 4/scratch register\n" + " * v1 r4 register variable\n" + " * v2 r5 register variable\n" + " * v3 r6 register variable\n" + " * v4 r7 register variable\n" + " * v5 r8 register variable\n" + " * sb/v6 r9 static base/register variable\n" + " * sl/v7 r10 stack limit/stack chunk handle/reg. variable\n" + " * fp r11 frame pointer\n" + " * ip r12 scratch register/new-sb in inter-link-unit calls\n" + " * sp r13 lower end of current stack frame\n" + " * lr r14 link address/scratch register\n" + " * pc r15 program counter\n" + " *******************************************************************/\n\n" + "/*******************************************************************\n" + " * Included Files\n" + " *******************************************************************/\n\n" + "/*******************************************************************\n" + " * Definitions\n" + " *******************************************************************/\n\n" + "/* The __ARM_ARCH define is provided by gcc 4.8. Construct it otherwise. */\n" + "#ifndef __ARM_ARCH\n" + "# ifdef __ARM_ARCH_2__\n" + "# define __ARM_ARCH 2\n" + "# elif defined (__ARM_ARCH_3__) || defined (__ARM_ARCH_3M__)\n" + "# define __ARM_ARCH 3\n" + "# elif defined (__ARM_ARCH_4__) || defined (__ARM_ARCH_4T__)\n" + "# define __ARM_ARCH 4\n" + "# elif defined (__ARM_ARCH_5__) || defined (__ARM_ARCH_5E__) \\\n" + " || defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_5TE__) \\\n" + " || defined(__ARM_ARCH_5TEJ__)\n" + "# define __ARM_ARCH 5\n" + "# elif defined (__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \\\n" + " || defined (__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) \\\n" + " || defined (__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__)\n" + "# define __ARM_ARCH 6\n" + "# elif defined (__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \\\n" + " || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \\\n" + " || defined(__ARM_ARCH_7EM__)\n" + "# define __ARM_ARCH 7\n" + "# else\n" + "# error unknown arm architecture\n" + "# endif\n" + "#endif\n\n" + "#if __ARM_ARCH > 4 || defined (__ARM_ARCH_4T__)\n" + "# define ARCH_HAS_BX\n" + "#endif\n" + "#if __ARM_ARCH > 4\n" + "# define ARCH_HAS_BLX\n" + "#endif\n" + "#if defined(ARCH_HAS_BX)\n" + "#define BX(x) bx\t##x\n" + "#else\n" + "#define BX(x) mov\tpc, ##x\n" + "#endif\n\n"; + +static const char import_prologue[] = ""; + +/******************************************************************* + * Import Function Name String Table + *******************************************************************/ + +static const char import_name_strtab_prologue[] = + "\n/*******************************************************************\n" + " * Import Function Names\n" + " *******************************************************************/\n\n" + "/* These are the names of all of the functions that are imported.\n" + " * Notice that all data associated with the library names is retained\n" + " * in the .text section." + " */\n\n" + "\t.text\n" + "\t.align\t0\n"; + +#define MKIMPSTRTABARG(fn,i) (i), (i), (i), (fn), (i), (i) + +static const char import_name_strtab_format[] = + "\n\t.local\t__dynimport%04d\n" + "\t.type\t__dynimport%04d, object\n\n" + "__dynimport%04d:\n" + "\t.asciz\t\"%s\"\n" + "\t.size\t__dynimport%04d, .-__dynimport%04d\n"; + +/******************************************************************* + * Dyanamic Call Information + *******************************************************************/ + +static const char dynimport_decl_prologue[] = + "\n/*******************************************************************\n" + " * Imported Symbol Table (an array of type struct flat_import)\n" + " *******************************************************************/\n\n" + "/* Notice that, unlike most other arrays in this file, this array\n" + " * is declared to reside in .data. Because of this, there will be\n" + " * per-process instances of this table.\n" + " */\n\n" + "\t.data\n" + "\t.align\t2\n\n" + "\t.global\t__dynimport_begin\n" + "\t.type\t__dynimport_begin, object\n" + "\t.global\t__dynimport_end\n" + "\t.type\t__dynimport_end, object\n\n"; + +#define MKINFODECLARGS(fn, i) (i), (fn), (i) + +static const char dynimport_decl_format[] = + "\t.local\t__dyninfo%04d\t/* Dynamic info for imported symbol %s */\n" + "\t.type\t__dyninfo%04d, object\n"; + +static const char dynimport_array_prologue[] = + "\n__dynimport_begin:\n"; + +#define MKINFOARGS(fn, i) (i), (fn), (i), (i), (i) + +static const char dynimport_array_format[] = + "__dyninfo%04d:\t\t\t/* Dynamic info for imported symbol %s */\n" + "\t.word\t__dynimport%04d\t/* Offset to name of imported function */\n" + "\t.word\t0\t\t/* Resolved address of imported function */\n" + "\t.size\t__dyninfo%04d, .-__dyninfo%04d\n"; + +static const char dynimport_array_epilogue[] = + "__dynimport_end:\n" + "\t.size\t__dynimport_begin, __dynimport_end-__dynimport_begin\n"; + +static const char dyncall_decl_prologue[] = + "\n/*******************************************************************\n" + " * Dynamic Call Logic\n" + " *******************************************************************/\n\n" + "\t.text\n" + "\t.align\t2\n"; + +#define MKCALLARGS(fn, i) (fn), (fn), (fn), (fn), (i), (i), (i), (fn), (fn) + +#ifndef __NO_GOT__ + +static const char dyncall_format[] = + "\n/* Dynamic call logic for imported symbol %s */\n\n" + "\t.global\t%s\n" + "\t.type\t%s, function\n\n" + "%s:\n" + "\tldr\tip,.Ldyn%04d\n" + "\tadd\tip,ip,sl\n" + "\tldr\tip,[ip,#4]\n" + "\tBX(ip)\n" + ".Ldyn%04d:\n" + "\t.word\t__dyninfo%04d(GOTOFF)\n" + "\t.size\t%s, .-%s\n"; + +static const char nonreturning_dyncall_format[] = + "\n/* Dynamic call logic for imported, non-returning symbol %s */\n\n" + "\t.global\t%s\n" + "\t.type\t%s, function\n\n" + "%s:\n" + "\tldr\tip,.Ldyn%04d\n" + "\tadd\tip,ip,sl\n" + "\tldr\tip,[ip,#4]\n" + "\tBX(ip)\n" + ".Ldyn%04d:\n" + "\t.word\t__dyninfo%04d(GOTOFF)\n" + "\t.size\t%s, .-%s\n"; + +#else + +static const char dyncall_format[] = + "\n/* Dynamic call logic for imported symbol %s */\n\n" + "\t.global\t%s\n" + "\t.type\t%s, function\n\n" + "%s:\n" + "\tldr\tip,.Ldyn%04d\n" + "\tadd\tip,ip,sl\n" + "\tldr\tip,[ip,#4]\n" + "\tBX(ip)\n" + ".Ldyn%04d:\n" + "\t.word\t__dyninfo%04d\n" + "\t.size\t%s, .-%s\n"; + +static const char nonreturning_dyncall_format[] = + "\n/* Dynamic call logic for imported, non-returning symbol %s */\n\n" + "\t.global\t%s\n" + "\t.type\t%s, function\n\n" + "%s:\n" + "\tldr\tip,.Ldyn%04d\n" + "\tadd\tip,ip,sl\n" + "\tldr\tip,[ip,#4]\n" + "\tBX(ip)\n" + ".Ldyn%04d:\n" + "\t.word\t__dyninfo%04d\n" + "\t.size\t%s, .-%s\n"; + +#endif + +/******************************************************************* + * File Epilogue + *******************************************************************/ + +static const char file_epilogue[] = + "\t.end\n"; + + + + diff --git a/tools/nxflat/dyncall_skeleton_thumb2.def b/tools/nxflat/dyncall_skeleton_thumb2.def new file mode 100644 index 00000000000..5d4b81c126d --- /dev/null +++ b/tools/nxflat/dyncall_skeleton_thumb2.def @@ -0,0 +1,222 @@ +/*********************************************************************** + * toolchain/nxflat/thumb2/dyncall_skeleton.def + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <[email protected]> + * + * 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. + * + ***********************************************************************/ + +/******************************************************************* + * File Prologue + *******************************************************************/ + +static const char file_prologue[] = + "/*******************************************************************\n" + " *\n" + " * This file contains the dynamic call logic that performs the thunk\n" + " * for outound calls from one module to another.\n" + " *\n" + " * ARM register quick reference:\n" + " *\n" + " * Name Number ARM Procedure Calling Standard Role\n" + " *\n" + " * a1 r0 argument 1/integer result/scratch register/argc\n" + " * a2 r1 argument 2/scratch register/argv\n" + " * a3 r2 argument 3/scratch register/envp\n" + " * a4 r3 argument 4/scratch register\n" + " * v1 r4 register variable\n" + " * v2 r5 register variable\n" + " * v3 r6 register variable\n" + " * v4 r7 register variable\n" + " * v5 r8 register variable\n" + " * sb/v6 r9 static base/register variable\n" + " * sl/v7 r10 stack limit/stack chunk handle/reg. variable\n" + " * fp r11 frame pointer\n" + " * ip r12 scratch register/new-sb in inter-link-unit calls\n" + " * sp r13 lower end of current stack frame\n" + " * lr r14 link address/scratch register\n" + " * pc r15 program counter\n" + " *******************************************************************/\n\n" + "\t.syntax\tunified\n" + "\t.thumb\n\n" + "/*******************************************************************\n" + " * Included Files\n" + " *******************************************************************/\n\n" + "/*******************************************************************\n" + " * Definitions\n" + " *******************************************************************/\n"; + +static const char import_prologue[] = ""; + +/******************************************************************* + * Import Function Name String Table + *******************************************************************/ + +static const char import_name_strtab_prologue[] = + "\n/*******************************************************************\n" + " * Import Function Names\n" + " *******************************************************************/\n\n" + "/* These are the names of all of the functions that are imported.\n" + " * Notice that all data associated with the library names is retained\n" + " * in the .text section." + " */\n\n" + "\t.text\n" + "\t.align\t0\n"; + +#define MKIMPSTRTABARG(fn,i) (i), (i), (i), (fn), (i), (i) + +static const char import_name_strtab_format[] = + "\n\t.local\t__dynimport%04d\n" + "\t.type\t__dynimport%04d, object\n\n" + "__dynimport%04d:\n" + "\t.asciz\t\"%s\"\n" + "\t.size\t__dynimport%04d, .-__dynimport%04d\n"; + +/******************************************************************* + * Dyanamic Call Information + *******************************************************************/ + +static const char dynimport_decl_prologue[] = + "\n/*******************************************************************\n" + " * Imported Symbol Table (an array of type struct flat_import)\n" + " *******************************************************************/\n\n" + "/* Notice that, unlike most other arrays in this file, this array\n" + " * is declared to reside in .data. Because of this, there will be\n" + " * per-process instances of this table.\n" + " */\n\n" + "\t.data\n" + "\t.align\t2\n\n" + "\t.global\t__dynimport_begin\n" + "\t.type\t__dynimport_begin, object\n" + "\t.global\t__dynimport_end\n" + "\t.type\t__dynimport_end, object\n\n"; + +#define MKINFODECLARGS(fn, i) (i), (fn), (i) + +static const char dynimport_decl_format[] = + "\t.local\t__dyninfo%04d\t/* Dynamic info for imported symbol %s */\n" + "\t.type\t__dyninfo%04d, object\n"; + +static const char dynimport_array_prologue[] = + "\n__dynimport_begin:\n"; + +#define MKINFOARGS(fn, i) (i), (fn), (i), (i), (i) + +static const char dynimport_array_format[] = + "__dyninfo%04d:\t\t\t/* Dynamic info for imported symbol %s */\n" + "\t.word\t__dynimport%04d\t/* Offset to name of imported function */\n" + "\t.word\t0\t\t/* Resolved address of imported function */\n" + "\t.size\t__dyninfo%04d, .-__dyninfo%04d\n"; + +static const char dynimport_array_epilogue[] = + "__dynimport_end:\n" + "\t.size\t__dynimport_begin, __dynimport_end-__dynimport_begin\n"; + +static const char dyncall_decl_prologue[] = + "\n/*******************************************************************\n" + " * Dynamic Call Logic\n" + " *******************************************************************/\n\n" + "\t.text\n" + "\t.align\t2\n"; + +#define MKCALLARGS(fn, i) (fn), (fn), (fn), (fn), (i), (i), (i), (fn), (fn) + +#ifndef __NO_GOT__ + +static const char dyncall_format[] = + "\n/* Dynamic call logic for imported symbol %s */\n\n" + "\t.global\t%s\n" + "\t.type\t%s, function\n" + "\t.thumb_func\n\n" + "%s:\n" + "\tldr\tip,.Ldyn%04d\n" + "\tadd\tip,ip,sl\n" + "\tldr\tip,[ip,#4]\n" + "\tbx\tip\n" + ".Ldyn%04d:\n" + "\t.word\t__dyninfo%04d(GOTOFF)\n" + "\t.size\t%s, .-%s\n"; + +static const char nonreturning_dyncall_format[] = + "\n/* Dynamic call logic for imported, non-returning symbol %s */\n\n" + "\t.global\t%s\n" + "\t.type\t%s, function\n" + "\t.thumb_func\n\n" + "%s:\n" + "\tldr\tip,.Ldyn%04d\n" + "\tadd\tip,ip,sl\n" + "\tldr\tip,[ip,#4]\n" + "\tbx\tip\n" + ".Ldyn%04d:\n" + "\t.word\t__dyninfo%04d(GOTOFF)\n" + "\t.size\t%s, .-%s\n"; + +#else + +static const char dyncall_format[] = + "\n/* Dynamic call logic for imported symbol %s */\n\n" + "\t.global\t%s\n" + "\t.type\t%s, function\n" + "\t.thumb_func\n\n" + "%s:\n" + "\tldr\tip,.Ldyn%04d\n" + "\tadd\tip,ip,sl\n" + "\tldr\tip,[ip,#4]\n" + "\tbx\tip\n" + ".Ldyn%04d:\n" + "\t.word\t__dyninfo%04d\n" + "\t.size\t%s, .-%s\n"; + +static const char nonreturning_dyncall_format[] = + "\n/* Dynamic call logic for imported, non-returning symbol %s */\n\n" + "\t.global\t%s\n" + "\t.type\t%s, function\n" + "\t.thumb_func\n\n" + "%s:\n" + "\tldr\tip,.Ldyn%04d\n" + "\tadd\tip,ip,sl\n" + "\tldr\tip,[ip,#4]\n" + "\tbx\tip\n" + ".Ldyn%04d:\n" + "\t.word\t__dyninfo%04d\n" + "\t.size\t%s, .-%s\n"; + +#endif + +/******************************************************************* + * File Epilogue + *******************************************************************/ + +static const char file_epilogue[] = + "\t.end\n"; + + + + diff --git a/tools/nxflat/mknxflat.c b/tools/nxflat/mknxflat.c new file mode 100644 index 00000000000..8208fe1e8fc --- /dev/null +++ b/tools/nxflat/mknxflat.c @@ -0,0 +1,770 @@ +/**************************************************************************** + * tools/nxflat/mknxflat.c + * + * SPDX-License-Identifier: BSD-3-Clause + * SPDX-FileCopyrightText: 2009, 2018 Gregory Nutt. All rights reserved. + * SPDX-FileCopyrightText: 2002, 2006 Cadenux, LLC. All rights reserved. + * SPDX-FileContributor: Gregory Nutt <[email protected]> + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * mknxflat generates the "thunk" assembly file for an NXFLAT module: one + * stub per imported function, plus the import name string table and the + * per-process __dyninfo array the loader fills in at load time. + * + * This is a port of the tool from the NuttX buildroot NXFLAT toolchain. + * The one substantive change is that the symbol table is read from the ELF + * file directly rather than through libbfd. libbfd is GPL, which an Apache + * project cannot depend on, and it is awkward to obtain besides -- but the + * dependency was never deep: the upstream tool used it only to open the + * file and enumerate symbols, never to relocate or rewrite anything. + * + * The emitted text is unchanged. The format strings live in the .def + * files, which are carried here byte-for-byte from upstream. + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "nxflat_thunk.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define dbg(format, ...) \ + do \ + { \ + if (verbose) \ + { \ + printf(format, ##__VA_ARGS__); \ + } \ + } \ + while (0) + +/* Just enough of the ELF32 ABI to walk a symbol table. Spelled out here + * rather than pulled from <elf.h> so the tool builds on any host. + */ + +#define EI_NIDENT 16 +#define ELFCLASS32 1 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define SHT_SYMTAB 2 +#define SHT_DYNSYM 11 + +#define SHN_UNDEF 0 + +#define STB_WEAK 2 +#define STT_OBJECT 1 + +#define ELF_ST_BIND(i) ((i) >> 4) +#define ELF_ST_TYPE(i) ((i) & 0x0f) + +#define MAX_EXPORT_NAMES 1024 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct elf32_ehdr_s +{ + unsigned char e_ident[EI_NIDENT]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint32_t e_entry; + uint32_t e_phoff; + uint32_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +}; + +struct elf32_shdr_s +{ + uint32_t sh_name; + uint32_t sh_type; + uint32_t sh_flags; + uint32_t sh_addr; + uint32_t sh_offset; + uint32_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint32_t sh_addralign; + uint32_t sh_entsize; +}; + +struct elf32_sym_s +{ + uint32_t st_name; + uint32_t st_value; + uint32_t st_size; + unsigned char st_info; + unsigned char st_other; + uint16_t st_shndx; +}; + +/* One imported symbol, in symbol table order */ + +struct import_s +{ + char *name; + int is_object; + int is_weak; +}; + +typedef int (*namefunc_type)(const char *name, void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Command line settings (counters but treated like booleans) */ + +static int verbose = 0; +static int weak_imports = 0; +static int dsyms = 0; + +/* Characteristics of things */ + +static int calls_nonreturning_functions = 0; + +/* Names of things */ + +static const char *program_name = NULL; +static const char *elf_filename = NULL; +static const char *out_filename = NULL; + +/* The selected architecture's thunk format strings */ + +static const struct nxflat_thunk_s *thunk = NULL; + +/* The imported symbols, in symbol table order */ + +static struct import_s *imports = NULL; +static long number_undefined = 0; + +static int counter; + +/* Big-endian input? ARM is normally little-endian but big-endian ARM + * exists, so honour EI_DATA rather than assuming. + */ + +static int need_swap = 0; + +/**************************************************************************** + * Private constant data + ****************************************************************************/ + +/* This is the list of names of libc and libpthread functions that + * do not return. These may require some special handling -- at a + * minimum, they must tie up resources that can only be released + * when the function returns. + */ + +static const char *const nonreturners[] = +{ + "abort", /* Never returns */ + "exit", /* Never returns */ + "_exit", /* Never returns */ + "longjmp", /* Never returns */ + "_longjmp", /* Never returns */ + "pthread_exit", /* Never returns */ + "siglongjmp", /* Never returns */ + NULL +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: swap16 / swap32 + ****************************************************************************/ + +static uint16_t swap16(uint16_t v) +{ + return need_swap ? (uint16_t)((v >> 8) | (v << 8)) : v; +} + +static uint32_t swap32(uint32_t v) +{ + if (!need_swap) + { + return v; + } + + return ((v & 0x000000fful) << 24) | ((v & 0x0000ff00ul) << 8) | + ((v & 0x00ff0000ul) >> 8) | ((v & 0xff000000ul) >> 24); +} + +/**************************************************************************** + * Name: xread + * + * Description: + * Read exactly nbytes at an absolute offset, or die. + * + ****************************************************************************/ + +static void xread(int fd, void *buffer, size_t nbytes, off_t offset) +{ + ssize_t nread; + + if (lseek(fd, offset, SEEK_SET) == (off_t)-1) + { + fprintf(stderr, "%s: seek to %ld failed: %s\n", + elf_filename, (long)offset, strerror(errno)); + exit(2); + } + + while (nbytes > 0) + { + nread = read(fd, buffer, nbytes); + if (nread < 0) + { + if (errno == EINTR) + { + continue; + } + + fprintf(stderr, "%s: read failed: %s\n", + elf_filename, strerror(errno)); + exit(2); + } + else if (nread == 0) + { + fprintf(stderr, "%s: unexpected end of file\n", elf_filename); + exit(2); + } + + buffer = (char *)buffer + nread; + nbytes -= nread; + } +} + +/**************************************************************************** + * Name: load_imports + * + * Description: + * Collect every undefined, non-object symbol from the ELF file, in symbol + * table order. + * + * The selection rule is the upstream one. Symbol typing is not + * trustworthy here: imported functions are frequently emitted as + * STT_NOTYPE rather than STT_FUNC, while a weakly defined *object* does + * show up as an undefined object. So rather than looking for functions, + * this takes everything undefined that is not explicitly an object. A + * genuinely undefined object would be an error, and is left to the link. + * + ****************************************************************************/ + +static void load_imports(void) +{ + struct elf32_ehdr_s ehdr; + struct elf32_shdr_s *shdrs; + struct elf32_sym_s *syms; + char *strtab; + int wanted = dsyms ? SHT_DYNSYM : SHT_SYMTAB; + int symidx = -1; + size_t nsyms; + size_t strsize; + size_t i; + int fd; + + fd = open(elf_filename, O_RDONLY); + if (fd < 0) + { + fprintf(stderr, "%s: cannot open: %s\n", + elf_filename, strerror(errno)); + exit(2); + } + + xread(fd, &ehdr, sizeof(ehdr), 0); + + if (memcmp(ehdr.e_ident, "\177ELF", 4) != 0) + { + fprintf(stderr, "%s: not an ELF file\n", elf_filename); + exit(2); + } + + if (ehdr.e_ident[4] != ELFCLASS32) + { + fprintf(stderr, "%s: not a 32-bit ELF file\n", elf_filename); + exit(2); + } + + /* Decide whether the host and the object disagree about byte order */ + + { + const uint16_t probe = 1; + int host_le = *(const unsigned char *)&probe; + int obj_le = (ehdr.e_ident[5] == ELFDATA2LSB); + + need_swap = (host_le != obj_le); + } + + /* Re-read the fields that mattered now that byte order is known */ + + ehdr.e_shoff = swap32(ehdr.e_shoff); + ehdr.e_shnum = swap16(ehdr.e_shnum); + ehdr.e_shentsize = swap16(ehdr.e_shentsize); + + if (ehdr.e_shnum == 0 || ehdr.e_shentsize != sizeof(struct elf32_shdr_s)) + { + fprintf(stderr, "%s: no usable section header table\n", elf_filename); + exit(2); + } + + shdrs = malloc((size_t)ehdr.e_shnum * sizeof(struct elf32_shdr_s)); + if (shdrs == NULL) + { + fprintf(stderr, "Failed to allocate section headers\n"); + exit(3); + } + + xread(fd, shdrs, (size_t)ehdr.e_shnum * sizeof(struct elf32_shdr_s), + ehdr.e_shoff); + + for (i = 0; i < ehdr.e_shnum; i++) + { + shdrs[i].sh_type = swap32(shdrs[i].sh_type); + shdrs[i].sh_offset = swap32(shdrs[i].sh_offset); + shdrs[i].sh_size = swap32(shdrs[i].sh_size); + shdrs[i].sh_link = swap32(shdrs[i].sh_link); + shdrs[i].sh_entsize = swap32(shdrs[i].sh_entsize); + + if ((int)shdrs[i].sh_type == wanted && symidx < 0) + { + symidx = (int)i; + } + } + + if (symidx < 0) + { + fprintf(stderr, "%s: no %s section\n", elf_filename, + dsyms ? "dynamic symbol table" : "symbol table"); + exit(2); + } + + if (shdrs[symidx].sh_entsize != sizeof(struct elf32_sym_s)) + { + fprintf(stderr, "%s: unexpected symbol entry size\n", elf_filename); + exit(2); + } + + nsyms = shdrs[symidx].sh_size / sizeof(struct elf32_sym_s); + + syms = malloc(shdrs[symidx].sh_size); + if (syms == NULL) + { + fprintf(stderr, "Failed to allocate symbol table\n"); + exit(3); + } + + xread(fd, syms, shdrs[symidx].sh_size, shdrs[symidx].sh_offset); + + /* The linked string table holds the names */ + + if (shdrs[symidx].sh_link >= ehdr.e_shnum) + { + fprintf(stderr, "%s: symbol table has no string table\n", + elf_filename); + exit(2); + } + + strsize = shdrs[shdrs[symidx].sh_link].sh_size; + strtab = malloc(strsize + 1); + if (strtab == NULL) + { + fprintf(stderr, "Failed to allocate string table\n"); + exit(3); + } + + xread(fd, strtab, strsize, shdrs[shdrs[symidx].sh_link].sh_offset); + strtab[strsize] = '\0'; + + close(fd); + + imports = calloc(nsyms, sizeof(struct import_s)); + if (imports == NULL) + { + fprintf(stderr, "Failed to allocate import table\n"); + exit(3); + } + + for (i = 0; i < nsyms; i++) + { + uint32_t st_name = swap32(syms[i].st_name); + uint32_t st_value = swap32(syms[i].st_value); + uint16_t st_shndx = swap16(syms[i].st_shndx); + unsigned char info = syms[i].st_info; + + if (st_shndx != SHN_UNDEF || st_value != 0 || st_name == 0 || + st_name >= strsize) + { + continue; + } + + if (ELF_ST_TYPE(info) == STT_OBJECT) + { + /* An undefined object is not something a thunk can stand in + * for; leave it to the link to complain. + */ + + continue; + } + + imports[number_undefined].name = &strtab[st_name]; + imports[number_undefined].is_object = 0; + imports[number_undefined].is_weak = + (ELF_ST_BIND(info) == STB_WEAK); + number_undefined++; + } + + free(shdrs); + free(syms); + + dbg("Found %ld undefined symbols\n", number_undefined); +} + +/**************************************************************************** + * Name: traverse_undefined_functions + ****************************************************************************/ + +static int traverse_undefined_functions(void *arg, namefunc_type fn) +{ + long i; + + for (i = 0; i < number_undefined; i++) + { + /* Is it imported as a "weak" symbol? If so, we will process the + * symbol only if we were requested to do so from the command line. + */ + + if (imports[i].is_weak && weak_imports == 0) + { + continue; + } + + if (fn(imports[i].name, arg) != 0) + { + return 1; + } + } + + return 0; +} + +/**************************************************************************** + * Name: put_string + ****************************************************************************/ + +static void put_string(int fd, const char *string) +{ + ssize_t bytes_available = strlen(string); + ssize_t bytes_written = write(fd, string, bytes_available); + + if (bytes_written < 0) + { + fprintf(stderr, + "Failed to write %ld bytes of string to output, errno=%d\n", + (long)bytes_available, errno); + exit(5); + } + else if (bytes_written != bytes_available) + { + fprintf(stderr, "Only wrote %ld of %ld bytes of string to output\n", + (long)bytes_written, (long)bytes_available); + exit(6); + } +} + +/**************************************************************************** + * Name: does_not_return_name + ****************************************************************************/ + +static int does_not_return_name(const char *func_name) +{ + int i; + + for (i = 0; nonreturners[i] != NULL; i++) + { + if (strcmp(func_name, nonreturners[i]) == 0) + { + return 1; + } + } + + return 0; +} + +static int check_nonreturning(const char *func_name, void *arg) +{ + if (does_not_return_name(func_name)) + { + calls_nonreturning_functions = 1; + } + + return 0; +} + +/**************************************************************************** + * Name: put_import_name_strtab / put_dynimport_decl / ... + * + * Description: + * The four emission passes. Each walks the import list in the same + * order, so the %04d counters line up across passes. + * + ****************************************************************************/ + +static int put_import_name(const char *func_name, void *arg) +{ + char buffer[4096]; + int fd = *(int *)arg; + + snprintf(buffer, sizeof(buffer), thunk->import_name_strtab_format, + counter, counter, counter, func_name, counter, counter); + put_string(fd, buffer); + counter++; + return 0; +} + +static int put_dynimport_decl(const char *func_name, void *arg) +{ + char buffer[4096]; + int fd = *(int *)arg; + + snprintf(buffer, sizeof(buffer), thunk->dynimport_decl_format, + counter, func_name, counter); + put_string(fd, buffer); + counter++; + return 0; +} + +static int put_dynimport_array(const char *func_name, void *arg) +{ + char buffer[4096]; + int fd = *(int *)arg; + + snprintf(buffer, sizeof(buffer), thunk->dynimport_array_format, + counter, func_name, counter, counter, counter); + put_string(fd, buffer); + counter++; + return 0; +} + +static int put_dyncall(const char *func_name, void *arg) +{ + char buffer[4096]; + int fd = *(int *)arg; + const char *format; + + if (does_not_return_name(func_name)) + { + format = thunk->nonreturning_dyncall_format; + } + else + { + format = thunk->dyncall_format; + } + + snprintf(buffer, sizeof(buffer), format, + func_name, func_name, func_name, func_name, + counter, counter, counter, func_name, func_name); + put_string(fd, buffer); + counter++; + return 0; +} + +/**************************************************************************** + * Name: show_usage + ****************************************************************************/ + +static void show_usage(void) +{ + fprintf(stderr, "Usage: %s [options] <elf-filename>\n\n", program_name); + fprintf(stderr, "Where options are one or more of the following. Note\n"); + fprintf(stderr, "that a space is always required between the option and\n"); + fprintf(stderr, "any following arguments.\n\n"); + fprintf(stderr, " -a <arch>\n"); + fprintf(stderr, " Instruction set of the module: arm or thumb2\n"); + fprintf(stderr, " [thumb2]\n"); + fprintf(stderr, " -d Use dynamic symbol table. [symtab]\n"); + fprintf(stderr, " -o <out-filename>\n"); + fprintf(stderr, " Output to <out-filename> [stdout]\n"); + fprintf(stderr, " -v Verbose output [no output]\n"); + fprintf(stderr, " -w Import weakly declared functions, i.e., weakly\n"); + fprintf(stderr, " declared functions are expected to be provided at\n"); + fprintf(stderr, " load-time [not imported]\n"); + fprintf(stderr, "\n"); + exit(1); +} + +/**************************************************************************** + * Name: parse_args + ****************************************************************************/ + +static void parse_args(int argc, char **argv) +{ + const char *arch = "thumb2"; + int opt; + + program_name = argv[0]; + + while ((opt = getopt(argc, argv, "a:do:vw")) != -1) + { + switch (opt) + { + case 'a': + arch = optarg; + break; + + case 'd': + dsyms++; + break; + + case 'o': + out_filename = optarg; + break; + + case 'v': + verbose++; + break; + + case 'w': + weak_imports++; + break; + + default: + show_usage(); + break; + } + } + + if (strcmp(arch, "thumb2") == 0) + { + thunk = &g_thunk_thumb2; + } + else if (strcmp(arch, "arm") == 0) + { + thunk = &g_thunk_arm; + } + else + { + fprintf(stderr, "Unrecognized architecture '%s'\n\n", arch); + show_usage(); + } + + if (optind >= argc) + { + fprintf(stderr, "No ELF file provided\n\n"); + show_usage(); + } + + elf_filename = argv[optind]; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, char **argv, char **envp) +{ + int fd = 1; + + parse_args(argc, argv); + + if (out_filename != NULL) + { + fd = open(out_filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) + { + fprintf(stderr, "Failed to open %s: %s\n", out_filename, + strerror(errno)); + exit(4); + } + } + + load_imports(); + + traverse_undefined_functions(NULL, check_nonreturning); + + /* Output the thunk file in the same order the upstream tool used: + * prologue, import name string table, the __dyninfo declarations, the + * __dyninfo array, then the call thunks. + */ + + put_string(fd, thunk->file_prologue); + put_string(fd, thunk->import_prologue); + + put_string(fd, thunk->import_name_strtab_prologue); + counter = 0; + traverse_undefined_functions(&fd, put_import_name); + + put_string(fd, thunk->dynimport_decl_prologue); + counter = 0; + traverse_undefined_functions(&fd, put_dynimport_decl); + + put_string(fd, thunk->dynimport_array_prologue); + counter = 0; + traverse_undefined_functions(&fd, put_dynimport_array); + put_string(fd, thunk->dynimport_array_epilogue); + + put_string(fd, thunk->dyncall_decl_prologue); + counter = 0; + traverse_undefined_functions(&fd, put_dyncall); + + put_string(fd, thunk->file_epilogue); + + if (fd != 1) + { + close(fd); + } + + return 0; +} diff --git a/tools/nxflat/nxflat_thunk.h b/tools/nxflat/nxflat_thunk.h new file mode 100644 index 00000000000..b2870c70cd1 --- /dev/null +++ b/tools/nxflat/nxflat_thunk.h @@ -0,0 +1,79 @@ +/**************************************************************************** + * tools/nxflat/nxflat_thunk.h + * + * SPDX-License-Identifier: BSD-3-Clause + * SPDX-FileCopyrightText: 2009, 2018 Gregory Nutt. All rights reserved. + * SPDX-FileCopyrightText: 2002, 2006 Cadenux, LLC. All rights reserved. + * SPDX-FileContributor: Gregory Nutt <[email protected]> + * + * 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 __TOOLS_NXFLAT_NXFLAT_THUNK_H +#define __TOOLS_NXFLAT_NXFLAT_THUNK_H + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* The set of format strings that make up one architecture's thunk file. + * + * The upstream tool selected these at compile time through an "arch" + * symlink pointing at either arm/ or thumb2/. A symlink cannot be carried + * in the repository, and one host binary has to serve boards of both + * flavours -- lpc31xx is ARM while lpc17xx, tiva, stm32f1 and rp23xx are + * Thumb-2 -- so the choice moves to a runtime "-a" option instead. The + * .def files themselves are unmodified, so the emitted text is unchanged. + */ + +struct nxflat_thunk_s +{ + const char *file_prologue; + const char *import_prologue; + const char *import_name_strtab_prologue; + const char *import_name_strtab_format; + const char *dynimport_decl_prologue; + const char *dynimport_decl_format; + const char *dynimport_array_prologue; + const char *dynimport_array_format; + const char *dynimport_array_epilogue; + const char *dyncall_decl_prologue; + const char *dyncall_format; + const char *nonreturning_dyncall_format; + const char *file_epilogue; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +extern const struct nxflat_thunk_s g_thunk_arm; +extern const struct nxflat_thunk_s g_thunk_thumb2; + +#endif /* __TOOLS_NXFLAT_NXFLAT_THUNK_H */ diff --git a/tools/nxflat/thunk_arm.c b/tools/nxflat/thunk_arm.c new file mode 100644 index 00000000000..5c0ba813b4a --- /dev/null +++ b/tools/nxflat/thunk_arm.c @@ -0,0 +1,62 @@ +/**************************************************************************** + * tools/nxflat/thunk_arm.c + * + * SPDX-License-Identifier: BSD-3-Clause + * SPDX-FileCopyrightText: 2009, 2018 Gregory Nutt. All rights reserved. + * SPDX-FileCopyrightText: 2002, 2006 Cadenux, LLC. All rights reserved. + * SPDX-FileContributor: Gregory Nutt <[email protected]> + * + * 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. See the .def file + * included below, which is carried unmodified from the upstream NuttX + * buildroot NXFLAT toolchain. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "nxflat_thunk.h" + +/* The format strings are file-scope statics inside the .def, so each + * architecture gets its own translation unit and the two sets cannot + * collide. The .def is byte-for-byte the upstream file. + */ + +#include "dyncall_skeleton_arm.def" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +const struct nxflat_thunk_s g_thunk_arm = +{ + file_prologue, + import_prologue, + import_name_strtab_prologue, + import_name_strtab_format, + dynimport_decl_prologue, + dynimport_decl_format, + dynimport_array_prologue, + dynimport_array_format, + dynimport_array_epilogue, + dyncall_decl_prologue, + dyncall_format, + nonreturning_dyncall_format, + file_epilogue +}; diff --git a/tools/nxflat/thunk_thumb2.c b/tools/nxflat/thunk_thumb2.c new file mode 100644 index 00000000000..f7d05fc1ccc --- /dev/null +++ b/tools/nxflat/thunk_thumb2.c @@ -0,0 +1,62 @@ +/**************************************************************************** + * tools/nxflat/thunk_thumb2.c + * + * SPDX-License-Identifier: BSD-3-Clause + * SPDX-FileCopyrightText: 2009, 2018 Gregory Nutt. All rights reserved. + * SPDX-FileCopyrightText: 2002, 2006 Cadenux, LLC. All rights reserved. + * SPDX-FileContributor: Gregory Nutt <[email protected]> + * + * 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. See the .def file + * included below, which is carried unmodified from the upstream NuttX + * buildroot NXFLAT toolchain. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "nxflat_thunk.h" + +/* The format strings are file-scope statics inside the .def, so each + * architecture gets its own translation unit and the two sets cannot + * collide. The .def is byte-for-byte the upstream file. + */ + +#include "dyncall_skeleton_thumb2.def" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +const struct nxflat_thunk_s g_thunk_thumb2 = +{ + file_prologue, + import_prologue, + import_name_strtab_prologue, + import_name_strtab_format, + dynimport_decl_prologue, + dynimport_decl_format, + dynimport_array_prologue, + dynimport_array_format, + dynimport_array_epilogue, + dyncall_decl_prologue, + dyncall_format, + nonreturning_dyncall_format, + file_epilogue +};
