-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Kernel Build Apps #12356
Comments
Hi @MainframeReboot please enable Debug Scheduler Info and Debug FileSystem Info, it will report more info showing why it is failing. Look at sched/init/nx_bringup.c line 379, probably it is failing here:
|
Yes, this is the line it's failing at. I understand this is due to the file system needing to be mounted but I am trying to understand if there's a way to compile the nsh library into the kernel or if I have to perform a |
I don't know if I understood correctly what you want to do and what you are doing, but let to highlight some points: in kernel build mode NuttX is very similar to Linux, it means it will need to mount the userspace to execute the "init" application. I think you only need to use "make export" when you are building external ELFs, to be loaded later on, when the system is already running. For example to create a ELF program to be loaded from SDCard or USB Thumb Drive. Maybe @xiaoxiang781216 @patacongo @lupyuen other could help me to understand what you want to do. |
@MainframeReboot I believe NuttX PolarFire Icicle is producing Relocatable ELF Binaries that are not Fully-Linked (which contains Relocation Symbols)? There's a patch for QEMU RISC-V that produces Fully-Linked ELF Binaries, maybe this will help: https://github.com/lupyuen/quickjs-nuttx#full-linking-for-nuttx-apps The patch is here: #11524 |
To use the kernel builds, you need to have two blobs: (1) the kernel binary, and (2) the root file system. The root file system must contain an executable called "init" that is started when by the kernel during initialization. The root file system can be provided via external media such as SD card or in-memory as a ROMFS file system. There are two separate builds. If you build a KERNEL build configuration, you get only the kernel blob. To build the ROMFS init file system you have to invent something else. There are some simple examples in the tree. There used to be a README.txt file describing how to do the ROMFS build, but it has been removed or, perhaps, moved to another location. Yes, using the export files can be helpful. Here is some discussion: @lupyuen does this all of the time and probably has a more user friendly solution. |
No, that is not possible. NSH uses only user space OS interfaces. These cannot (or at least should not) be used inside of the OS. Also, each process lives inside a protected address space. If NSH were in the kernel, it could not interact with anything in user space and vice versa.
That is mostly because there are no shared libraries. As a consequence, a lot of C library code must be duplicated in each process. There is a lot of room for improvement for KERNEL build tools to make things cleaner. Wouldn't it be nice if there were a elf-nuttx- toolchain that could build efficient ELF modules as simply as GLIBC and GCC make build Linux processes? You can reduce the amount of C library code in the module by reducing the size of the symbol table that draws the code into the link. |
Hi All, Thank you for your replies and the direction, I've definitely learned a lot. I have gone down the road of exporting NuttX, importing it into the I can confirm that from the debug messages that the file system is being mounted, no issues here. However, I do seem to run into problems whenit attempts to load the program I'm not quite sure what this means other than my address environments are incorrectly set? |
Hi @MainframeReboot I'm happy to know that you are evolving with your testings! (Suggestion: if you have a blog, create a post documenting the path you are following, it could help more people in the future, even your future you). This error message is coming from here:
I don't know much about RV64 arch, but I think you are putting the userspace init ELF at wrong position, maybe the function explanation rings a bell:
|
Thanks for your reply @acassis. I can definitely look into a blog post of my findings once I get this to work! I took a look, and I am not sure where the init ELF is supposed to go. I built the apps, generated a I followed the link that @lupyuen posted above and have been successful in generating fully linked applications that are significantly smaller in size. I should mention that before I performed the full link of the apps I did some reach into the address environments and the MMU. While doing this I stumbled upon another article written by @lupyuen covering the MMU: https://lupyuen.codeberg.page/articles/mmu.html. Using what I learned in this article, I set my address environment as follows:
Then I configured the I am still attempting to get the default icicle knsh config to run with minor tweaks based on articles I read as well as other RISC-V configs. I have noticed that the icicle knsh config has In the meantime, if anyone has another other suggestions I could try I would greatly appreciate it. |
Nice findings @MainframeReboot ! Seems like finally the code is loading, but an exception Instruction page fault (MCAUSE = 0x0c) is happening. Maybe @lupyuen has some tips to track this issue because I saw it in his PureScript dump parser. I noted that you are doing the board initialization in the AppBringUp thread, did you try avoid it? Disabling CONFIG_BOARD_LATE_INITIALIZE ? I don't think it will solve the root cause, but at least can have some different effect. Regarding the blog, I suggest you write down each logical decision and testing you are doing, this will help you later when you write the post. Remember: when you arrive at your destination you won't remember all the trees you saw along the way. |
Careful. There are several knsh or kostest configurations that are used in the PROTECTED build. That PROTECTED build is for MCUs that don't have MMUs, but rather MPUs and, hence, don't support virtual addressing. Make sure that you only look at configurations that have CONFIG_BUILD_KERNEL=y |
Hi @MainframeReboot: The RISC-V Exception looks interesting: EXCEPTION: Instruction page fault.
MCAUSE: 0x0C
EPC: 0x00
MTVAL: 0x00
Segmentation fault in PID 4: /bin/init EPC says that the NSH Shell is trying to execute the code at Address 0 and failing? This is very odd. It's possible that the Stack Size is too small (8KB): binfmt_dumpmodule:
stacksize: 8192 Could you increase the Stack Size to 64KB? ("Default task_spawn Stack Size" and "Thread Local Storage") https://lupyuen.github.io/articles/quickjs#nuttx-stack-is-full-of-quickjs It's also possible that Full Linking of NSH Shell messed up the code addresses. I wonder why NuttX doesn't show the full Crash Dump, it might show us the code that's trying to execute Address 0. Hmmm... |
Is zero a valid address in this architecture? In ARM architectures, reset vectors are configurable but often are at virtual address zero and must never be re-mapped. I suspect this exception occurs immediately on startup of /bin/init. Is zero the correct process startup address in the link? The startup address should be in the ELF header. Is the MMU configured properly to execute from address zero? Sorry... more questions than answers. |
Great questions, they're very helpful in pointing me in directions I wouldn't have looked otherwise. I took a peak at the output while building the apps and noticed that the linker prints out: I will look into the MMU configuration next but I'm confused why it's attempting to run from address 0 if the entry point in the header is listed as 0xC0000000. |
Thanks for the suggestion, I will give this a try and let you know the result. One thing I am noticing right away is that |
I don't know enough about RISC-V to be much help. For ELF modules, __start is defined in crt0.c. crt0 must be linked into all ELF modules.
[crt0 is where shared library support would be implemented someday. C++ needs a crt1 and crtN to handle constructors and destructors.] But, perhaps, RISC-V follows a different model??? I think you need to make sure that crt0 is being built and linked into the ELF module. One possibility is that crt0 with __start is not being including in the ELF module link. That would be the case if nothing references it. It can be forced into the link with arguments on the link command line. In the RISC-V Makefile you will find:
That will do the job if crt0 is built and included in the link. |
Thank you all so much for your help. The recent suggestions pointed me down the right path and I can confirm that init now loads: To get this to work, I took a look at the crt0.c source file mentioned by @patacongo as well as the linker scripts in the ../apps folder. I noticed that the entry point in the apps linker files does include crt0.o during linking but the entry point I also took the advice from @lupyuen and looked at the thread local storage configuration. As mentioned in my previous reply this wasn't set at all, so I added @acassis, As I don't yet have a blog, I will document the other changes I had to make as the knsh defconfig for the mpfs icicle kit required additional modifications in order to work (not in chronological order):
csr_write(CSR_PMPADDR0, -1);
csr_write(CSR_PMPCFG0, (PMP_A_NAPOT | PMP_R | PMP_W | PMP_X));
riscv-none-elf-objcopy --strip-unneeded init
riscv-none-elf-objcopy --strip-unneeded hello
riscv-none-elf-objcopy --strip-unneeded helloxx
riscv-none-elf-objcopy --strip-unneeded sh
# HSS Payload Generator
# First, we can optionally set a name for our image, otherwise one will be created dynamically
set-name: 'PolarFire-SoC-HSS::nuttxbsp_kernel_payload'
# Next, we'll define the entry point addresses for each hart, as follows:
hart-entry-points: {u54_1: '0x80000000', u54_2: '0x80000000', u54_3: '0x80000000', u54_4: '0x80000000>
#
payloads:
nuttxbsp.bin: {exec-addr: '0x80000000', owner-hart: u54_1, priv-mode: prv_s, skip-opensbi: true} After all of that, NuttX kernel build runs on the PolarFire Icicle kit. Although I am running into an issue getting I noticed Thank you again @patacongo, @lupyuen, @acassis and @pussuw for your support on getting this to work. |
A good candidate for that page fault would be C++ ctors/dtors trying to execute with kernel privileges. The same crt0 file should handle those per process, however I have seen places where the ctor/dtor code is executed in binfmt (there is a kconfig that controls this I believe, don't remember the name though). You should check for that. RISC-V quite smartly prohibits executing user mapped code segments with raised privileges. This is done unconditionally and it cannot be bypassed (not by design, nor by accident). |
Constructors and destructors should run in crti and crtN, respectively, for general Unix compatibility. crti should support __init and crtN should supporrt __fini. Lots more detail if you care about this: https://gcc.gnu.org/onlinedocs/gccint/Initialization.html As the OP mentioned, this is currently done with conditional logic in crt0. That is technically okay but will likely confuse people who are used to thinking about things in the GCC/GLIBC way. There is a long-open issue #1265 (and related #1263). Perhaps this is only a problem in PROTECTED mode which as a single set of ctors and dtors for the whole user-space blob. KERNEL mode uses only loadable ELF modules, each with their own ctors and dtors. crt0.c exists only for armv7-a, arm64, and riscv-5 all of which can support the KERNEL build. So crt0 with C++ ELF modules should never be used in PROTECTED mode right now or else you would get doubly constructed static classes.
That is CONFIG_BINFMT_CONSTRUCTORS. I think that should be disabled in KERNEL mode to let the ELF module call its own constructors and destructors in the correct context. This seems awkward and prone to errors to me. |
Congratulations @MainframeReboot !!! I'm glad to know you got it working. Since you don't have a blog, I have a better suggestion: Please submit it a guide "Running NuttX in kernel mode (with MMU support) on Microchip PolarFire Icicle board". So it could be included here: https://nuttx.apache.org/docs/latest/guides/index.html Just create it inside nuttx/Documentation/guides/ so it will be available as reference for everybody using this board. |
I naively enabled CONFIG_BINFMT_CONSTRUCTORS as the prompt told me that it enables "C++ Static Constructor Support" so it seemed like something I should enable. I have turned this off. However, that alone did not solve the issue. I had to remove the calls Regardless, I can live with NuttX kernel build that has no C++ static constructor support given everything else appears to be working flawlessly. |
exec_ctors() is really simple, but it depends on a table of constructor addresses created by the build logic. These are defined by binfmt/libelf/gnu-elf.ld or similar:
Check whatever linker script you use to build the elf modules. Check that those symbols exist in the module. These define a table of constructor and destructor address. Constructors start at _sctors and end at _ectors. Make sure that there are constructors in the table. Issues with atexit() may be like those of #1263. I don't know the state of that issue. The function called by atexit() calls the destructors. So more likely that is the same issue as with the list of destructors.
But you shouldn't have to! |
I fixed #1263 a while back (years back), so that should not be an issue here. However CONFIG_BINFMT_CONSTRUCTORS can cause such issues. I use C++ almost exclusively with BUILD_KERNEL, it works just fine. There is something odd about your build environment still, hope you can find it! |
I decided not to settle and poked around more to see if I can get static constructor support to work but no luck so far. I have taken a look and The segmentation fault appears to happen inside the function I dumped helloxx and examined the symbol table to make sure .ctors was there and it is: My linker script is based on the linker script from the Fully Linking for NuttX apps article by @lupyuen and looks as follows:
I can confirm the initial address |
I sat down and RTFM to fully understand the differences between crt0, crt1, crti, crtbegin, crtn and crtend. This has helped me immensely and I have managed to get static global instances to run on NuttX kernel by making the necessary changes to NuttX. I will explain my patches below but the executive summary is use crt0 for C, use crt1 for C++ while also manually linking crti, crtbegin, crtn and crtend for C++ applications only. crt0.cThe first modification was to remove C++ logic from crt0. This means that all of the .ctors/.dtors arrays at the top (_sctors, sdtors etc.) are removed, along with the the calls to exec_ctors and atexit(exec_dtors). The result is a crt0.c file that looks like this (some comments stripped for size): /****************************************************************************
* arch/risc-v/src/common/crt0.c
****************************************************************************/
#include <nuttx/arch.h>
#include <nuttx/addrenv.h>
#include <nuttx/compiler.h>
#include <nuttx/config.h>
#include <sys/types.h>
#include <syscall.h>
#include <stdlib.h>
#include <stdio.h>
#include "riscv_internal.h"
#ifdef CONFIG_BUILD_KERNEL
int main(int argc, char *argv[]);
static void sig_trampoline(void) naked_function;
static void sig_trampoline(void)
{
__asm__ __volatile__
(
" addi sp, sp, -" STACK_FRAME_SIZE "\n" /* Save ra on the stack */
REGSTORE " ra, 0(sp)\n"
" mv t0, a0\n" /* t0=sighand */
" mv a0, a1\n" /* a0=signo */
" mv a1, a2\n" /* a1=info */
" mv a2, a3\n" /* a2=ucontext */
" jalr t0\n" /* Call the signal handler (modifies ra) */
REGLOAD " ra, 0(sp)\n" /* Recover ra in sp */
" addi sp, sp, " STACK_FRAME_SIZE "\n"
" li a0, %0\n" /* SYS_signal_handler_return */
" ecall\n" /* Return from the SYSCALL */
" nop\n"
:
: "i" (SYS_signal_handler_return)
:
);
}
void __start(int argc, char *argv[])
{
int ret;
/* Initialize the reserved area at the beginning of the .bss/.data region
* that is visible to the RTOS.
*/
ARCH_DATA_RESERVE->ar_sigtramp = (addrenv_sigtramp_t)sig_trampoline;
/******************************************************************
* Do NOT include C++ constructor/destructor calls in this file.
* This file is for C applications only. Refer to crt1.c for C++.
*******************************************************************/
/* Call the main() entry point passing argc and argv. */
ret = main(argc, argv);
/* Call exit() if/when the main() returns */
exit(ret);
}
#endif /* CONFIG_BUILD_KERNEL */ crt1.cAll C++ constructor/destructor logic was moved to the new file crt1.c. Note that this is dfference from the original C++ logic in crt0.c. I have learned, during my research, that .ctors and .dtors is the "old" way of doing things and that the new recommended way of doing things is to use .preinit_array, .init_array and .fini_array. The RISC-V toolchain that I use (xPack 13.2.0) supports the new way so I have decided to follow the new convention. From my reading of old RISC-V NuttX issues, it appears the NuttX team has moved on to xPack 13.2.0 for testing so it should work with other RISC-V boards as well. Here is the new crt1.c file: /****************************************************************************
* arch/risc-v/src/common/crt1.c
****************************************************************************/
#include <nuttx/arch.h>
#include <nuttx/addrenv.h>
#include <nuttx/compiler.h>
#include <nuttx/config.h>
#include <sys/types.h>
#include <syscall.h>
#include <stdlib.h>
#include "riscv_internal.h"
#ifdef CONFIG_BUILD_KERNEL
int main(int argc, char *argv[]);
static void sig_trampoline(void) naked_function;
static void sig_trampoline(void)
{
__asm__ __volatile__
(
" addi sp, sp, -" STACK_FRAME_SIZE "\n" /* Save ra on the stack */
REGSTORE " ra, 0(sp)\n"
" mv t0, a0\n" /* t0=sighand */
" mv a0, a1\n" /* a0=signo */
" mv a1, a2\n" /* a1=info */
" mv a2, a3\n" /* a2=ucontext */
" jalr t0\n" /* Call the signal handler (modifies ra) */
REGLOAD " ra, 0(sp)\n" /* Recover ra in sp */
" addi sp, sp, " STACK_FRAME_SIZE "\n"
" li a0, %0\n" /* SYS_signal_handler_return */
" ecall\n" /* Return from the SYSCALL */
" nop\n"
:
: "i" (SYS_signal_handler_return)
:
);
}
/****************************************************************************
* Public Data
****************************************************************************/
/*
Linker defined symbols to .preinit_array, .init_array and .fini_array.
.ctors and .dtors are not used by RISC-V.
*/
extern initializer_t __preinit_array_start[];
extern initializer_t __preinit_array_end[];
extern initializer_t __init_array_start[];
extern initializer_t __init_array_end[];
extern initializer_t __fini_array_start[];
extern initializer_t __fini_array_end[];
/****************************************************************************
* Private Functions
****************************************************************************/
#ifdef CONFIG_HAVE_CXX
/****************************************************************************
* Name: exec_preinit
*
* Description:
* Calls startup functions prior to main entry point
*
****************************************************************************/
static void exec_preinit(void)
{
initializer_t *preinit;
for(preinit = __preinit_array_start; preinit < __preinit_array_end; ++preinit)
{
initializer_t initializer = *preinit;
if (initializer)
{
initializer();
}
}
}
/****************************************************************************
* Name: exec_init
*
* Description:
* Calls static constructors prior to main entry point
*
****************************************************************************/
static void exec_init(void)
{
initializer_t *init;
for(init = __init_array_start; init < __init_array_end; ++init)
{
initializer_t initializer = *init;
if (initializer)
{
initializer();
}
}
}
/****************************************************************************
* Name: exec_fini
*
* Description:
* Calls static destructors using atexit
*
****************************************************************************/
static void exec_fini(void)
{
initializer_t *fini;
for(fini = __fini_array_start; fini < __fini_array_end; ++fini)
{
initializer_t initializer = *fini;
if (initializer)
{
initializer();
}
}
}
#endif
void __start(int argc, char *argv[])
{
int ret;
/* Initialize the reserved area at the beginning of the .bss/.data region
* that is visible to the RTOS.
*/
ARCH_DATA_RESERVE->ar_sigtramp = (addrenv_sigtramp_t)sig_trampoline;
#ifdef CONFIG_HAVE_CXX
/* Call preinit functions */
exec_preinit();
/* Call C++ constructors */
exec_init();
/* Setup so that C++ destructors called on task exit */
atexit(exec_fini);
#endif
/* Call the main() entry point passing argc and argv. */
ret = main(argc, argv);
/* Call exit() if/when the main() returns */
exit(ret);
}
#endif /* CONFIG_BUILD_KERNEL */ gnu-elf.ldIn order to make sure the arrays in the crt1.c file are populated, the linker script was updated to match:
Compilation & LinkingI had to modify how my kernel applications were compiled and linked in order to support the new crt0.c and crt1.c files. To do this, I modified the file(GLOB CSTARTUP_OBJS ${NUTTX_PATH}/startup/*)
file(GLOB CXXSTARTUP_OBJS ${NUTTX_PATH}/startup/*)
add_compile_options($<$COMPILE_LANGUAGE:C>:-nostdlib>)
add_compile_options($<$COMPILE_LANGUAGE:CXX>:-nodefaultlibs$<SEMICONON>-nostartfiles>)
set(CMAKE_C_LINK_EXECUTABLE
"<CMAKE_LINKER> ${LDFLAGS} --entry=__start -T${LINKER_SCRIPT} <OBJECTS> ${CSTARTUP_OBJS} -o <TARGET> <LINK_LIBRARIES> -L${NUTTX_PATH}/libs --start-group ${LDLIBS} ${EXTRA_LIBS} --end-group"
)
set(CMAKE_CXX_LINK_EXECUTABLE
"<CMAKE_LINKER> ${LDFLAGS} --entry=__start -T${LINKER_SCRIPT} <OBJECTS> ${CXXSTARTUP_OBJS} -o <TARGET> <LINK_LIBRARIES> -L${NUTTX_PATH}/libs --start-group ${LDLIBS} ${EXTRA_LIBS} --end-group"
) The above modifications ensure that C++ is not linked with any standard libraries nor is it linked with any toolchain start files (I do this manually later on) while C is. It also splits the STARTUP_OBJS variable into a CSTARTUP_OBJS and a CXXSTARTUP_OBJS variable so I can set one to crt0.o and the other to crt1.o. The modification to STARTUP_OBJS is done in Inside the crt0$(OBJEXT): %$(OBJEXT): %.c
$(call COMPILE, $<, $@)
crt1$(OBJEXT): %$(OBJEXT): %.c
$(call COMPILE, $<, $@) Additionally, I had to make sure crt1.o was exported when export_startup: $(CSTARTUP_OBJS) $(CXXSTARTUP_OBJS)
ifneq ($(CSTARTUP_OBJS),)
$(Q) if [ -d "$(EXPORT_DIR)/startup" ]; then \
cp -f $(CSTARTUP_OBJS) "$(EXPORT_DIR)/startup/."; \
else \
echo "$(EXPORT_DIR)/startup does not exist"; \
exit 1; \
fi
endif
ifneq ($(CXXSTARTUP_OBJS),)
$(Q) if [ -d "$(EXPORT_DIR)/startup" ]; then \
cp -f $(CXXSTARTUP_OBJS) "$(EXPORT_DIR)/startup/."; \
else \
echo "$(EXPORT_DIR)/startup does not exist"; \
exit 1; \
fi
endif Now that my crt0.o and crt1.o files are built and exported, I had to make sure they were used while building my apps. To do this, I modified the ARCHCFLAGS += -fno-common -pipe
ARCHCXXFLAGS += -fno-common -nostdinc++ -pipe -nodefaultlibs -nostartfiles As I am manually linking the C runtime files for C++, I also added some variables to the top of the file for these objects: ARCHCRT0OBJ = $(call CONVERT_PATH,$(TOPDIR)$(DELIM)startup$(DELIM)crt0$(OBJEXT))
ARCHCRT1OBJ = $(call CONVERT_PATH,$(TOPDIR)$(DELIM)startup$(DELIM)crt1$(OBJEXT))
ARCHCRTIOBJ = $(wildcard $(shell $(CC) $(ARCHCPUFLAGS) --print-file-name=crti.o))
ARCHCRTBEGINOBJ = $(wildcard $(shell $(CC) $(ARCHCPUFLAGS) --print-file-name=crtbegin.o))
ARCHCRTENDOBJ = $(wildcard $(shell $(CC) $(ARCHCPUFLAGS) --print-file-name=crtend.o))
ARCHCRTNOBJ = $(wildcard $(shell $(CC) $(ARCHCPUFLAGS) --print-file-name=crtn.o)) The last modification involves the define ELFLDC
$(info From ELFLDC: $1 $2)
$(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) $(ARCHCRT0OBJ) $1 $(LDSTARTGROUP) $(LDLIBS) $(LDENDGROUP) -o $2
endef
define ELFLDCXX
$(info From ELFLDCXX: $1 $2)
$(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) $(ARCHCRT1OBJ) $(ARCHCRTIOBJ) $(ARCHCRTBEGINOBJ) $1 $(LDSTARTGROUP) $(LDLIBS) $(LDENDGROUP) $(ARCHCRTENDOBJ) $(ARCHCRTNOBJ) -o $2
endef
define ELFLD
$(ECHO_BEGIN)"LD: $2 "
$(if $(MAINCOBJ), $(call ELFLDC, $1, $2), $(call ELFLDCXX, $1, $2))
$(ECHO_END)
endef Now when I perform a The additional benefit is that C applications no longer have empty .preinit_array/.init_array/.fini_array sections and no longer call I apologize for this insanely long post, but I wanted to document this in the event anyone else wants to use NuttX kernel build with C++ apps and static global instances. I also apologize if my "hacks" are unsightly, I am not an expert at makefiles so I am sure I broke a number of best practices while coming up with this solution. I am hoping now that I have a solution it can be critiqued, and someone can let me know if this is an OK way of doing it. Nonetheless, I have learned a ton getting the NuttX kernel running on the Polarfire Icicle board and I couldn't have done it without your support, so thank you again! |
@patacongo @MainframeReboot should this arch/risc-v/src/common/crt1.c be submitted to inclusion into nuttx mainline? |
I would think so. On one hand it should be functionally equivalent, but this is the cannonically correct way to organize the logic and will also enable us to support the dynamic loader, ldso, and shared libraries in the future. @xiaoxiang781216 what do you think? |
I recall that crtbegin and crtend come from GCC, deriving from a file called crtstuff. I think these are essentially "libraries". I think they contain the configurable, Compiler specific parts for crt1 and crtn. crt1 and crtn are then provided by GLIBC for most architectures. I looked into GLIBC and it does follow this clean breakdown for most architectures, but not all of them. I think we should not get too tied into either GCC or GLIBC |
Fair enough. I do want to reiterate that the switch from all logic in crt0.c to a crt0.c and crt1.c approach didn't solve my issue alone. I had to modify how the apps were compiled and linked or else it either broke C applications, C++ applications or sometimes both. With that said, I understand this might only be relevant to my architecture and toolchain combination so pushing the modifications out to common makefiles is most likely not desirable. I'm interested to hear ideas on how this can be properly implemented to support all architectures. |
Hi,
I have NuttX starting up in kernel build but it fails to load the init ELF file and as such, nothing really happens:
I have read various documentation regarding building kernal apps which leads me down the road of performing a
make export
in the nuttx directory followed by amake import
in the apps directory. This produces an apps/bin folder but the files contained in this folder are all over 4MB in size and the resultingboot_romfsimg.h
file is over 40MB in size. Does this sound right? The resulting flat build outputs a binary that is <200kb in size so I am failing to understand why kernel build generates files this large.Is there an elegant way to do this? Any documentation that explains the proper way to build and run the NSH library in kernal mode?
The text was updated successfully, but these errors were encountered: