An executable engineering dynamic loading and debugging method based on RISC-V
By introducing a dynamic call runtime interface and function pointer table into the RISC-V processor, the problem of program loading and debugging in an environment without an MMU is solved, enabling flexible and efficient program loading and debugging, reducing the risk of source code leakage, and supporting adaptive debugging mode.
Patent Information
- Application Number
- CN202510217224.6
- Authority / Receiving Office
- CN · China
- Patent Type
- Patents(China)
- Current Assignee / Owner
- Filing Date
- 2025-02-26
- Publication Date
- 2026-01-23
- Estimated Expiration
- 2045-02-26
AI Technical Summary
RISC-V processors without an MMU cannot load .so dynamic libraries or ELF format programs. Loading static libraries requires compilation and packaging, which reduces release efficiency, increases debugging complexity, and poses a high risk of source code leakage.
The method for dynamic loading and debugging of executable projects based on RISC-V involves adding dynamically callable runtime interface functions written in assembly language to the main project, establishing a function pointer table to enable calls to main project functions, creating adaptive debug print information processing functions, isolating general-purpose register values, and modifying the linker configuration file to specify the executable project code address.
It enables flexible and efficient program loading and debugging, reduces program footprint, lowers the risk of source code leakage, and supports adaptive operation in different environments.
Smart Images

Figure CN120066614B_ABST
Abstract
Description
Technical Field
[0001] This invention relates to the field of RISC-V processor technology, and in particular to a method for dynamically loading and debugging executable projects based on RISC-V. Background Technology
[0002] Because CPUs without an MMU lack memory address translation and protection mechanisms, they typically cannot load .so dynamic libraries or ELF format programs based on a Linux environment. .so dynamic libraries are library files that are dynamically loaded and linked at runtime, allowing programs to share code and data, reducing memory usage and program size. However, the loading and management of dynamic libraries rely on the memory mapping and protection functions provided by the MMU, which CPUs without an MMU cannot provide, thus preventing the loading of .so dynamic libraries. Similarly, while ELF format programs contain rich execution information, their complex structure and MMU dependency typically prevent them from running directly on CPUs without an MMU.
[0003] Loading static libraries requires the linker to directly copy the code from the library into the final executable file. When a static library program is released, the entire software needs to be compiled and packaged to generate the target code. This makes it impossible to release static libraries separately, which greatly reduces release efficiency and flexibility.
[0004] Debugging individual static libraries requires carrying the entire project's source code, which not only increases debugging complexity but also reduces the confidentiality of the source code to some extent. Once the project's source code is leaked, the code details of all modules will be exposed. Summary of the Invention
[0005] Based on the above analysis, the present invention aims to provide a method for dynamic loading and debugging of executable projects based on RISC-V, in order to solve the problem of inconvenience in program loading and debugging caused by the relatively fixed calling method of function interfaces between existing RISC-V processor modules.
[0006] This invention provides a method for dynamically loading and debugging executable projects based on RISC-V. It generates a main project and an independent executable project from an original project containing static libraries. A dynamic call interface function written in assembly language is added to the main project, enabling the main project to load the executable file generated by the executable project.
[0007] Create a function pointer table in the executable project that calls functions in the main project, thus enabling the calling of functions in the main project;
[0008] Dynamic debugging is performed on the main project and the independent executable project respectively. During the debugging process, an adaptive processing function for debugging print information is created so that the program can automatically identify the current environment. If it is in a debugging environment, it will output debugging information normally. If it is in a non-debugging environment, the program can skip the interruption instruction for outputting debugging information and continue running.
[0009] Furthermore, a function pointer table is established in the executable project to call functions in the main project. When the main project calls the executable project code through the dynamic call runtime interface function, the executable project passes the function pointer table to the main project. After receiving the function pointer table, the main project assigns the actual function address according to the function name in the function pointer table. The function pointer in the executable project obtains the actual address, which enables the calling of functions in the main project.
[0010] Furthermore, dynamic debugging of the executable project includes: opening the executable project with IDE software, entering debug mode, changing the filename after the load_image instruction in the Python script to the main program name of the executable project, adding an instruction to the Python script to define the main program entry address of the executable project, and executing the modified Python script.
[0011] Furthermore, the creation of an adaptive handling function for debug print information includes: adding an exception interrupt function that is called when a debug print information interrupt is triggered by the ebreak instruction; and creating an initialization function for the output function bsp_printfx(), which is used to check the current code execution environment.
[0012] Furthermore, the initialization function is used to set the exception vector mtvec to the address of the exception interrupt function, while saving the old vector value. If the current mode is debug mode, it enters the output function bsp_printfx(). In non-debug mode, if the CPU experiences an exception interrupt, it enters the exception interrupt function. In the exception interrupt function, it sets the code to force entry into the next instruction after the interrupt, so as to avoid the program being unable to continue running due to the interrupt instruction.
[0013] Furthermore, the executable project generation process includes: modifying the executable project's link configuration file to specify the executable project code address; modifying the executable project environment initialization process code to enable it to return to the main project, and isolating the values stored in the general-purpose registers of the executable project from those of the general-purpose registers of the main project.
[0014] Furthermore, the main project generation process includes: removing the static library files from the original project that contains the static library, and changing the original project's method of calling the static library by its function name to a method of dynamically calling the executable project using function pointers.
[0015] Furthermore, the dynamic call to the runtime interface function includes: setting the ra general-purpose register to store the address of the executable project returning to the main project, the a0 general-purpose register to store the entry address of the executable project code, and the a1 general-purpose register to store the function pointer table in the executable project; saving the values stored in the general-purpose registers other than x0 and a0 to a custom array, and jumping to the entry address of the executable project code through a jump instruction; after the executable project finishes execution, returning to the next instruction after the jump instruction, and restoring the values stored in all general-purpose registers and temporary registers saved in the custom array.
[0016] Furthermore, modifying the executable project's linker configuration file to specify the executable project code address includes: changing the executable project code address to an unused space.
[0017] Furthermore, the main project adds an interface function to initialize function pointers, including: creating a structure array, where each element of the structure array is assigned the address of a function in the executable project that the static library function to be called by the main project is converted into.
[0018] Compared with the prior art, the present invention can achieve at least one of the following beneficial effects:
[0019] 1. This invention provides a method for dynamically loading and debugging executable projects based on RISC-V. It generates a main project and an independent executable project based on the original project containing static libraries. A dynamic call interface function written in assembly language is added to the main project, enabling the main project to load the executable file generated by the executable project. This reduces the program's space footprint and also reduces the risk of source code leakage of the executable project.
[0020] 2. This invention achieves the calling of main project functions by establishing a function pointer table in the executable project; modifying the executable project's link configuration file to specify the executable project code address; modifying the executable project's environment initialization process code to enable it to return to the main project, and isolating the values stored in the executable project's general-purpose registers from those in the main project; removing the static library file from the original project containing the static library, and changing the original project's method of calling the static library by its function name to a method of dynamically calling the executable project by function pointers; thus, it enables the main project to flexibly load the static functions replaced by the executable project without having to copy the functions from the executable project to the main project, and the executable project can also call functions in the main project through function pointers, providing a flexible and efficient method for dynamic program loading.
[0021] 3. In the debugging process, this invention creates an adaptive processing function for debugging print information, enabling the program to automatically recognize the current environment. If in a debugging environment, it outputs debugging information normally; if in a non-debugging environment, the program skips the debugging information output interruption instruction and continues running. This avoids the need for the print information output function bsp_printfx() to be enabled in debug mode and disabled in release mode, thus enabling adaptive operation in both modes.
[0022] In this invention, the above-described technical solutions can be combined with each other to achieve more preferred combinations. Other features and advantages of this invention will be set forth in the following description, and some advantages may become apparent from the description or be learned by practicing the invention. The objects and other advantages of this invention can be realized and obtained from what is particularly pointed out in the description and drawings. Attached Figure Description
[0023] The accompanying drawings are for illustrative purposes only and are not intended to limit the invention. Throughout the drawings, the same reference numerals denote the same parts.
[0024] Figure 1 This is a flowchart of a method for dynamically loading and debugging executable projects based on RISC-V according to the present invention. Detailed Implementation
[0025] Preferred embodiments of the present invention will now be described in detail with reference to the accompanying drawings, which form part of this application and are used together with the embodiments of the present invention to illustrate the principles of the present invention, but are not intended to limit the scope of the present invention.
[0026] A specific embodiment of the present invention discloses a method for dynamically loading and debugging executable projects based on RISC-V, such as... Figure 1 As shown. The specific steps include S1-S4.
[0027] S1. Generate the main project and an independent executable project based on the original project containing static libraries.
[0028] The executable project generation process includes: modifying the executable project's linker configuration file to specify the executable project code address; modifying the executable project environment initialization process code to enable it to return to the main project, and isolating the values stored in the general-purpose registers of the executable project from those of the general-purpose registers of the main project.
[0029] Modifying the executable project's linker configuration file to specify the executable project's code address includes: changing the executable project's code address to an unused space.
[0030] Specifically, since the CPU's memory is uniformly distributed, the address space of each module needs to be pre-allocated. This is done by modifying the defaul.ld table, which defines the entry address of the executable project code and the space range it occupies.
[0031] This embodiment modifies the code in the defaul.ld table as follows:
[0032]
[0033] Modify the executable project environment initialization process code to isolate the executable project registers from the main project general-purpose register parameters. This includes: pushing the values of general-purpose registers a0 and a1 onto the stack in the executable project environment initialization process code; restoring the values of general-purpose registers a0 and a1 from the stack after the executable project finishes execution; and restoring the space of the stack pointer SP.
[0034] Specifically, the executable project's startup code, start.S, is modified. This code initializes the C language environment before entering main. The original start.S code, after executing `call main`, enters an infinite loop, assuming the main function has finished executing and thus completing its task, and performs no further operations. However, after being changed to an independently running module, start.S not only still initializes the executable project's own C language environment but also receives parameters from the function pointer table called by the main function. Upon entering the main function, the executable project must assign its interface function addresses to this function pointer table. Simultaneously, it must return CPU execution to the main program.
[0035] The modifications to the start.S code include: protecting the three values ra, a0, and a1 passed from the main project and pushing them onto the stack; ra being the address of the returned main project and a1 being the function pointer table in the main project; restoring the values of ra, a0, and a1 from the stack before executing the call main instruction (returning to the main project); allowing the executable project to obtain the table through the argv parameter of the main function main in the main project; completing the transfer of the table from the main project to the executable project; and handing it over to the main project's BIN_Init() for concretization.
[0036] The modified code in start.S of this embodiment includes:
[0037] Protect the three values ra, a0, and a1 passed from the main project and push them onto the stack:
[0038] addi sp,sp,-16
[0039] sw ra,12(sp)
[0040] sw a0,8(sp)
[0041] sw a1,4(sp)
[0042] Restore the values of ra, a0, and a1 from the stack space:
[0043] lw a0,8(sp)
[0044] lw a1,4(sp)
[0045] lw ra,12(sp)
[0046] addi sp,sp,16
[0047] ret
[0048] The main project generation process includes: removing the static library files from the original project that contains static libraries, and changing the original project's method of calling static libraries by static library function names to a method of dynamically calling executable projects by function pointers.
[0049] Specifically, the number of static libraries required by the original project is equal to the number of independent executable projects generated. Each static library corresponds to an independent executable project. This allows each static library to be developed, tested, and released independently, reducing development and maintenance costs.
[0050] This embodiment divides the original project into a main project and an executable project, enabling the main project to dynamically load executable projects (multiple executable projects are possible). Furthermore, "dynamic loading" means that instead of the static library code being linked to the main project only during the compilation phase, the executable project's code can now be loaded into memory after the main project starts running, and then executed by the main project's code.
[0051] Modify the executable project environment initialization process code to enable the executable project to return to the main project. This includes: pushing the value of the ra general-purpose register onto the stack in the executable project environment initialization process code, and restoring the value of the ra general-purpose register pushed onto the stack from the stack after the executable project finishes execution, so that the executable project can return to the main project.
[0052] To isolate the values stored in the executable project registers from those in the main project general-purpose registers, the compiler also includes adding an option to disable the GP global register in the compilation conditions.
[0053] S2. Add a dynamically called runtime interface function written in assembly language to the main project so that the main project can load the executable file generated by the executable project.
[0054] The dynamic call to the runtime interface function includes: setting the ra general-purpose register to store the address of the executable project returning to the main project, the a0 general-purpose register to store the entry address of the executable project code, and the a1 general-purpose register to store the function pointer table in the executable project; saving the values stored in the general-purpose registers other than x0 and a0 to a custom array, and jumping to the entry address of the executable project code through a jump instruction; after the executable project finishes execution, returning to the next instruction after the jump instruction, and restoring the values stored in all general-purpose registers and temporary registers saved in the custom array.
[0055] The main project adds an interface function to initialize function pointers, including: creating a structure array, and assigning each element in the structure array the address of a function in the executable project that the static library function to be called by the main project is converted into.
[0056] Specifically, a dynamic call interface function written in assembly language is added to the main project. This function stores the address of the executable project returning to the main project in the `ra` general-purpose register, the `a0` general-purpose register stores the entry address of the executable project code, and the `a1` general-purpose register stores the function pointer table in the executable project. The main project also adds an interface function that allows the executable project to obtain the function pointer table from the `argv` parameter of the main project's `main` function, thus completing the transfer of the function pointer table from the main project to the executable project.
[0057] Specifically, through step S1, a main project and one or more independent executable projects have been created. Since RISC V has 32 general-purpose registers, the values stored in these registers must be isolated by the protection mechanisms of the main project and each executable project. However, x0 is a constant zero register and does not require backup. a0 is the return value of the executable project, and it is not desirable to restore the original value of a0 in the main program of the main project when the executable project returns to the main project; therefore, a0 does not need backup. The executable project runs independently (similar to a dynamic library call), and the main project needs to dynamically find the dynamic source code of the executable project through the function pointer initialization interface function. In RISC V, since there is no MMU, the dynamic library compiler cannot find the function programming dynamics. This embodiment modifies the defaul.ld table, defining it as the entry address of the executable project code, so that the main project can dynamically find the entry address of the executable project code. The function pointer table is then passed through register a1 to find the addresses of each function in the executable project, enabling correct execution.
[0058] This function uses assembly to prevent the compiler from controlling the SP stack. The static library is changed to an independent executable project with a complete and independent C runtime environment, which requires protecting and isolating all registers in the CPU.
[0059] Dynamically calling the runtime interface function requires writing assembly code to protect and manage the SP stack (the stack pointer SP is an 8-bit register whose value is the address of the top of the stack, i.e., it points to the top of the stack; SP is the indirect address register for accessing the stack). A 124-byte array is created to store the 30 general-purpose registers of RISC-V (except for the RISC-V general-purpose register x0, which is a constant zero register and does not need to be backed up, and the a0 register, which is used as a return value and does not need to be backed up) and a temporary register (t0). When the main project calls the executable project, the two projects share the same SP register, so their environments will affect each other. To avoid this interference, the t0 register is used to store the values of all general-purpose registers into a 124-byte array. (At this point, the ra register is particularly important; it stores the return address of the dynamically called runtime interface function. The executable project is also responsible for protecting the values of the general-purpose registers during runtime. Because the executable project's code address is uncertain, the jalr long jump instruction `jalr ra,0` (a0) is used for execution. The dynamically called runtime interface function takes two parameters: a pointer variable a0 pointing to the executable project's code address, and a pointer variable a1 pointing to the function pointer table. After the jalr instruction is executed, the values from the 124-byte array are restored to the corresponding general-purpose registers (at this point, ra is also restored to the address that the main project should return to after running the executable project's executable file). Finally, the ret instruction returns CPU execution to the main project.)
[0060] S3. Create a function pointer table in the executable project to call functions in the main project, thus enabling the calling of functions in the main project.
[0061] In the executable project, a function pointer table is created that calls functions in the main project. When the main project calls the executable project code through the dynamic call runtime interface function, the executable project passes the function pointer table to the main project. After receiving the function pointer table, the main project assigns the actual function address according to the function name in the function pointer table. The function pointer in the executable project obtains the actual address, which enables the calling of functions in the main project.
[0062] Specifically, when an executable project needs the printf function for output, in the traditional sense, the executable project cannot be executed independently and needs to be linked with the main program. The printf function in the executable project can point to the main program through a function pointer.
[0063] S4. Perform dynamic debugging on the main project and the independent executable project respectively; during the debugging process, create an adaptive processing function for debugging print information so that the program can automatically identify the current environment. If it is in a debugging environment, it will output debugging information normally; if it is in a non-debugging environment, the program can skip the interruption instruction for outputting debugging information and continue running.
[0064] Dynamic debugging of an executable project includes: opening the executable project with IDE software, entering debug mode, changing the filename after the load_image instruction in the Python script to the main program name of the executable project, adding an instruction to the Python script to define the main program entry address of the executable project, and then executing the modified Python script.
[0065] Specifically, in the Efinity RISC-V IDE software, debugging is generally performed in project mode (static libraries cannot be run and debugged independently). The IDE software can only automatically load the ELF file of the current project during debugging. Therefore, additional ELF files need to be loaded via the OpenOCD command `load_image` on port 4444 (loading the ELF file of the executable project). To facilitate this, a special Python script was written.
[0066] A specific embodiment of the present invention includes:
[0067] Define the address and port of the OpenOCD Telnet server.
[0068] HOST="localhost"
[0069] PORT=4444
[0070] The command to be executed:
[0071] COMMAND="load_image MTbin.elf\n"
[0072] try:
[0073] Establish a Telnet connection:
[0074] tn=telnetlib.Telnet(HOST,PORT)
[0075] Read the initial welcome message
[0076] welcome_message=tn.read_until(b"Open On-Chip Debugger")
[0077] print(welcome_message.decode('ascii'))
[0078] Send command
[0079] tn.write(COMMAND.encode('ascii'))
[0080] This function reads the command execution result. The content to be read and the timeout can be adjusted according to the actual situation: `result = tn.read_until(b"downloaded", timeout = 50)`
[0081] print(result.decode('ascii'))
[0082] except Exception as e:
[0083] print(f"An error occurred: {e}")
[0084] finally:------ Ensure that the Telnet connection is closed regardless of whether an error occurs.
[0085] if'tn'in locals():
[0086] tn.close()
[0087] Specifically, when debugging the main project, after opening the main program of the main project using the IDE software, enter DEBUG mode and execute the Python script containing the ELF file with the main project name. The on-chip debugger OpenOCD's load_image command will automatically add the image to the corresponding memory space based on the information in the ELF file. Other operations remain unchanged.
[0088] When debugging an executable project, specify the entry address of the main program of the executable project.
[0089] After opening the executable project with the IDE software, enter DEBUG mode and execute the Python script.
[0090] Rename the filename after the function `load_image` to the name of the executable project's main program, and add the command `reg pc0x1000`. Declare the register variable `Program Counter PC` with a value of 0x1000 as the entry address of the executable project's main program.
[0091] The Efinity RISC-V IDE software provides a semihosting interface, the `bsp_printf` function (which redefines the output function to a specific hardware interface), allowing information to be displayed directly in the IDE's terminal window. However, this function only executes correctly in a debug environment. Outside of debug mode, during actual deployment, it will cause an abnormal interruption, affecting the program's normal operation. Enabling this function in debug mode and disabling it in deployment mode is inconvenient. To avoid repeatedly modifying the status code between debug and deployment, this embodiment optimizes the function to adapt to both modes.
[0092] Semihosting uses the ebreak instruction in RISC-V to allow the OpenOCD debugger to catch the exception and output the information to the IDE software terminal for display.
[0093] Creating an adaptive handling function for debug print information includes: adding an exception interrupt function that is called when a debug print information interrupt is triggered by the ebreak instruction; and creating an initialization function for the output function bsp_printfx(), which is used to check the current code execution environment.
[0094] The initialization function sets the exception vector mtvec to the address of the exception interrupt function and saves the old vector value. If the current mode is debug mode, it enters the output function bsp_printfx(). In non-debug mode, if the CPU experiences an exception interrupt, it enters the exception interrupt function. In the exception interrupt function, it sets the code to force entry into the next instruction after the interrupt, so as to avoid the program from being unable to continue running due to the interrupt instruction.
[0095] A specific embodiment of the adaptive handling function of this invention includes initializing the jtag_debugmode_check() function before creating the exception interrupt functions jtag_ebreak_trap_handler() and bsp_printfx(), including the following code:
[0096]
[0097]
[0098] Specifically, the `jtag_ebreak_trap_handler()` function is an exception interrupt function. In the absence of a simulator, it is called when the CPU triggers an interrupt caused by the `ebreak` instruction. The `jtag_debugmode_check()` function is an initialization function executed before `bsp_printfx()` (initialized only once). It checks the current code execution environment, first setting the exception vector `mtvec` (which needs to be restored after use), assigning `mtvec` to `jtag_ebreak_trap_handler()`, and saving the old vector value. Then, it triggers an interrupt by actively calling `bsp_printf()`. If an emulator exists in the current environment, this exception will be caught by the emulator and will not trigger a CPU exception interrupt. If not, a CPU exception interrupt will be triggered, and the `jtag_ebreak_trap_handler()` function will be entered. This indicates that no emulator exists, so `riscv_jtagmode` is set to 0. The `mret` instruction in this function is used to return to the point where the exception was triggered, i.e., `bsp_print()`. `csr_read(mepc)+4` is used to set the exception `mepc` to the next instruction. In the RISC-V system, `mepc` points to the triggered instruction by default. Then, the previous `mtvec` exception interrupt value is restored.
[0099] The new bsp_printfx() function internally uses the riscv_jtagmode variable to identify the current environment. If it is in JTAG mode, it will output normally; otherwise, it will not output debugging information.
[0100] Compared with existing technologies, the RISC-V-based dynamic loading and debugging method for executable projects provided in this embodiment generates a main project and an independent executable project based on the original project containing static libraries; a dynamic call runtime interface function written in assembly language is added to the main project, enabling the main project to load the executable file generated by the executable project; this reduces the program's footprint and also reduces the risk of executable project source code leakage. The loading method provided in this embodiment achieves the calling of main project functions by establishing a function pointer table in the executable project; modifying the executable project's link configuration file to specify the executable project code address; modifying the executable project's environment initialization process code to enable it to return to the main project, and isolating the values stored in the executable project's general-purpose registers from those in the main project; removing the static library file from the original project containing the static library, and changing the original project's method of calling the static library by its function name to a method of dynamically calling the executable project by function pointers; thus, it enables the main project to flexibly load the static functions replaced by the executable project without having to copy the functions from the executable project to the main project, and the executable project can also call functions in the main project through function pointers, which is a flexible and efficient dynamic program loading method. The debugging method provided in this embodiment creates an adaptive processing function for debugging print information in the debugging project, allowing the program to automatically recognize the current environment. If it is in a debugging environment, it outputs debugging information normally; if it is in a non-debugging environment, the program can skip the debugging information interruption instruction and continue running. This avoids the output function bsp_printfx() from being enabled in debug mode and disabled in release mode, allowing it to adapt to run in both different modes.
[0101] Those skilled in the art will understand that all or part of the processes of the methods described in the above embodiments can be implemented by a computer program instructing related hardware, and the program can be stored in a computer-readable storage medium. The computer-readable storage medium may be a disk, optical disk, read-only memory, or random access memory, etc.
[0102] The above description is only a preferred embodiment of the present invention, but the scope of protection of the present invention is not limited thereto. Any changes or substitutions that can be easily conceived by those skilled in the art within the scope of the technology disclosed in the present invention should be included within the scope of protection of the present invention.
Claims
1. A method for dynamically loading and debugging executable projects based on RISC-V, characterized in that, Generate a main project and a standalone executable project based on the original project containing static libraries; add a dynamically called runtime interface function written in assembly language to the main project so that the main project can load the executable file generated by the executable project; The function of dynamically calling the runtime interface includes: setting the ra general-purpose register to store the address of the executable project returning to the main project, the a0 general-purpose register to store the entry address of the executable project code, and the a1 general-purpose register to store the function pointer table in the executable project; saving the values stored in the general-purpose registers other than x0 and a0 to a custom array, and jumping to the entry address of the executable project code through a jump instruction; after the executable project finishes execution, returning to the instruction after the jump instruction, and restoring the values stored in all general-purpose registers and temporary registers saved in the custom array; Create a function pointer table in the executable project that calls functions in the main project, thus enabling the calling of functions in the main project; Dynamic debugging is performed on the main project and the independent executable project respectively. During the debugging process, an adaptive processing function for debugging print information is created so that the program can automatically identify the current environment. If it is in a debugging environment, it will output debugging information normally. If it is in a non-debugging environment, the program can skip the interruption instruction for outputting debugging information and continue running.
2. The executable project dynamic loading and debugging method according to claim 1, characterized in that, In the executable project, a function pointer table is created that calls functions in the main project. When the main project calls the executable project code through the dynamic call runtime interface function, the executable project passes the function pointer table to the main project. After receiving the function pointer table, the main project assigns the actual function address according to the function name in the function pointer table. The function pointer in the executable project obtains the actual address, which enables the calling of functions in the main project.
3. The executable project dynamic loading and debugging method according to claim 1, characterized in that, Dynamic debugging of an executable project includes: opening the executable project with IDE software, entering debug mode, changing the filename after the load_image instruction in the Python script to the main program name of the executable project, adding an instruction to the Python script to define the main program entry address of the executable project, and then executing the modified Python script.
4. The executable project dynamic loading and debugging method according to claim 1, characterized in that, Creating an adaptive handling function for debug print information includes: adding an exception interrupt function that is called when a debug print information interrupt is triggered by the ebreak instruction; and creating an initialization function for the output function bsp_printfx(), which is used to check the current code execution environment.
5. The executable project dynamic loading and debugging method according to claim 4, characterized in that, The initialization function sets the exception vector mtvec to the address of the exception interrupt function and saves the old vector value. If the current mode is debug mode, it enters the output function bsp_printfx(). In non-debug mode, if the CPU experiences an exception interrupt, it enters the exception interrupt function. In the exception interrupt function, it sets the code to force entry into the next instruction after the interrupt, so as to avoid the program from being unable to continue running due to the interrupt instruction.
6. The executable project dynamic loading and debugging method according to claim 1, characterized in that, The executable project generation process includes: modifying the executable project's linker configuration file to specify the executable project code address; modifying the executable project environment initialization process code to enable it to return to the main project, and isolating the values stored in the general-purpose registers of the executable project from those of the general-purpose registers of the main project.
7. The executable project dynamic loading and debugging method according to claim 1, characterized in that, The main project generation process includes: removing the static library files from the original project that contains static libraries, and changing the original project's method of calling static libraries by static library function names to a method of dynamically calling executable projects by function pointers.
8. The executable project dynamic loading and debugging method according to claim 6, characterized in that, Modifying the executable project's linker configuration file to specify the executable project's code address includes: changing the executable project's code address to an unused space.
9. The executable project dynamic loading and debugging method according to claim 7, characterized in that, The main project adds an interface function to initialize function pointers, including: creating a structure array, and assigning each element in the structure array the address of a function in the executable project that the static library function to be called by the main project is converted into.
Citation Information
Patent Citations
Remote debugging implementation method of embedded operating system
CN117472790A
Development loading method and device for decoupling internal modules of embedded software
CN117707540A