Overriding Weak ISR Handler from Assembly to C++ doesn't compile any code - c++

I am writing code for embedded programming on an ARM 32-bit based SAM D51 microprocessor using the IDE SEGGER Studio. I'm new to embedded programming and am writing my first interrupt.
The vector table with a dummy handler is written in ARM assembly, here's one example, the following code is auto-generated on project creation but marked as weak so it can be overridden in C/C++
ldr r0, =__stack_end__
mov sp, r0
bl SystemInit
b _start
.thumb_func
.weak SystemInit
SystemInit:
bx lr
Anywhere I read online says to simply add a C/C++ function with identical name and it's magically used by the linker because it's not marked as weak. Below is where I'm overriding it.
void SystemInit()
{
printf("Here");
}
However the debugger states that it can't place a breakpoint there because there's no code and in the disassembler it reveals that the entire function has been made into a comment with no code.
I've tried other functions including many of the handler functions but they all do the exact same thing and I have no idea why.
I've even tried forward declaring a weak function and then overriding it or marking the function as volatile. Here is my latest attempt but with the same result:
extern void __attribute__((weak)) SystemInit();
void SystemInit()
{
printf("Here");
}
and another attempt
volatile void SystemInit()
{
printf("Here");
}
They all end in no code being generated for the function and it appearing as a comment in disassembly.

Identifiers in C++ source files have their names mangled. The resulting linker function name is different from SystemInit. To stop C++ compiler from mangling the function name, declare the function with extern "C". That way generated function name will match the function name expected by the linker.

Related

Debug an AVR assembler project at source level

I want to debug a code of a plain assembler project for the ATmega2560. I want to use the Microchip debugger for that purpose. The goal is to get source level debugging with all variables and functions, breakpoints etc.
I managed to create a C "stub" file with a main() function that calls the assembler code.
extern int foo(int a);
int main(void)
{
int a = 0;
while (1)
{
a = foo(a);
}
}
But the assembler code also includes the interrupt vector table including the reset vector.
.extern main
.section .vectors
.global RESET_
RESET_: jmp WARM_0
.section code
.global foo
foo:
ret
WARM_0:
call main
ret
.end
Now I want to run the code from the label RESET_. The linker has placed the code in the section .vectors. That's okay so far, but the vector table from the GCC startup files are in that section before the vector table in my code. The GCC startup code must be removed to get my vector to the address 0. Therefore I activate the linker option "Do not use standard start files (-nostartfiles)". That gives the desired result: The reset vector has a jump to RESET_.
But this has the important side effect, that the debugger is not able to debug at source code level anymore. The C file with the main() function is still linked. But the source level debug support is lost.
How can I debug a plan assembler project with Microchip debugger/simulator for AVR8?
Remark: The code in the assembler file is not sufficient for a valid program. It's reduced to get a minimal example that should work in the Microchip environment.

arm-none-eabi-g++ does not correctly handle weak alias with -flto

I am programming an STM32F413 microcontroller with SystemWorkbench 4 stm32. The Interrupt vectors are defined in an assembly startup file as weak aliases like follows:
.weak TIM1_UP_TIM10_IRQHandler
.thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler
And referenced in an object like follows:
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.....
.word TIM1_UP_TIM10_IRQHandler
.....
So that the g_pfnVectors is a list of the addresses of the IRQ Handler functions. They are declared as weak aliases, so that if they are not defined by the user, the default handler is used.
I have defined the handler like this:
extern "C" {
void TIM1_UP_TIM10_IRQHandler() {
if (SU_TIM->SR & TIM_SR_UIF) {
SU_TIM->SR &= ~TIM_SR_UIF;
...
}
}
}
This works fine with the normal compiler optimization flags, however I wanted to try if I get smaller and possibly faster code with -flto (mainly for trying it, don't really needed it). But when compiling with -flto, g++ ignores my implementation of the handler and just uses the default handler, my handler isn't in the code at all.
So I tried to force g++ to include the function by adding __attribute__((used)) to the function definition, but it was still not compiled. However if I give it another name, then it was included in the binary. Also if I remove the weak alias and just have a reference to the handler in the startup file, it works too.
So somehow the weak aliases don't work with g++ link time optimization. Maybe someone can tell me what the error is and what I'm doing wrong here.
EDIT:
I have looked at which symbols are created with nm on the resulting .elf File, and the TIM1_UP_TIM10_IRQHandler is exported as a weak symbol with the address of the DefaultHandler. However when viewing just the .o file from the compilation unit containing the TIM1_UP_TIM10_IRQHandler function, it is exported as a symbol in the text section (T). So the linker, for some reason, chooses to keep the weak symbol, even though there is a strong symbol with the same name.
I think you should inform the compiler that it the interrupt __attribute__ ((interrupt ("IRQ"))), which is not needed normally as F4 has the stack by default aligned to 8 by the hardware.
If it does not help the workaround is to have a function pointer assigned with the handler, which will prevent it from discarding (if the pointer itself will not be discarded itself - check with your debugger).
The last resort - change the .s file with the vector table definitions
For those looking for this, still, there is apparently a confirmed bug in GCC 7 related to link-time optimization (-flto):
https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966
I have just run into this, again, with GCC 8 (gcc-arm-none-eabi-8-2019-q3-update release), the behavior is still the same.
The workaround that also works for me (from https://github.com/ObKo/stm32-cmake/issues/78) is to remove or comment the weak definitions at the end of the startup_XXX.s file, so change, for example
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
to
/*
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
*/
and replace them with your own implementation in a source file:
void NMI_Handler(void)
{
//...
}
All weak handlers need to be removed that are being called, so for example if you have UART1_Handler() defined in the HAL/LL drivers, you need to remove the corresponding .weak entry from the startup_XXX.s file, otherwise the interrupt will lock up the MCU by getting stuck in the default infinite loop, without executing the intended interrupt handler and returning from the interrupt, allowing other code execution to resume.
This bug is still present in gcc-arm-none-eabi-9-2020-q3-update but only for C handlers. Weirdly enough, handlers written in C++ (and declared with extern "C" linkage) are not anymore affected by this bug.
As another workaround, rather than messing with the startup.s file, I found that putting the IRQ handlers in separate .c files and building those (and only those) without LTO does the trick.
For those using CubeIDE and generating IRQ/HAL handlers with CubeMX (aka. "Device Configuration Tool"), all auto-generated handlers are in Core\Src\stm32XXXX_it.c, you just have to edit the properties of this file and remove LTO from the compilation options.
This is sub optimal, but it fits well with auto-generated IRQ/HAL handlers: only the first call (from IRQ handler to HAL handler) is unoptimized, but the HAL code itself is correctly optimized.

Forward a method without a signature

I'm trying to write a forwarding library for libEGL.dll so I can catch calls being passed through it for debug.
The problem is the library is missing 2 methods NvEglGetStdProcAddress and NvEglRegClientApi.
This is a C library built for Arm7 (WinCE). The header file I have for libEGL doesn't include these 2 methods so I have no idea what the signature is in order to forward the calls.
Is there any way of forwarding the calls without knowing the signature?
Could I disassemble the dll and look for the parameters being popped from the stack?
DumpBin shows these at RVA 0x217C and Ox1E5C, /ALL /DISASM shows the .text section starting at 0x11000. How do I translate between these two offsets?
I'm guessing this wouldn't work, Would it just leave the parameters on the stack and then mangle them slightly with the local variable? What would happen to the return value (if there is one?)
typedef void (*NvEglGetStdProcAddressFunc) (void);
void NvEglGetStdProcAddress()
{
NvEglGetStdProcAddressFunc ptr = (NvEglGetStdProcAddressFunc)GetProcAddress(hInst, _T("NvEglGetStdProcAddress"));
ptr();
}
You can simply forward export calls.
So my debug libEGL.dll .def file now has two extra lines at the top of it
; libEGL.def
EXPORTS
NvEglGetStdProcAddress = libEGLOld.NvEglGetStdProcAddress
NvEglRegClientApi = libEGLOld.NvEglRegClientApi
eglBindAPI
eglBindTexImage
...
A colleague of mine tested this and verified it works, although it also requires the ordinal to be specified

declaring an extern C function on template instantiation

I'm working on an MCU (STM32F4).
In the current system, all the interrupts handlers are declared as weak symbols in a link file, and if we want to use one, we just declare a function with the same name in C and it replaces the weak one at link time.
I'm trying to convert my system to C++, I envision a system where instantiating a certain interrupt type would declare the corresponding C function in the module.
I have no clue how to achieve that considering that extern "C" is forbidden for member functions.
any idea or alternative ?
My aim is to try to statically check some things and try to use some modern C++ in the field.
here is the current situation in C.
I have a assembly file with this thing in it:
g_pfnVectors:
.word _estack
.word Reset_Handler
(...)
.word SysTick_Handler
(...)
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
(...)
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
in my C code, I have that :
main() {
(...)
SysTick_Config(SystemCoreClock / cncMemory.parameters.clockFrequency);
while (1);
}
void SysTick_Handler(void) {
cncMemory.tick++;
}
And I envision something like:
int main() {
MCU<mySystickHandler, ...> mcu;
mcu.start();
}
static void mySystickHandler(void) {
cncMemory.tick++;
}
or something approaching (probably without the still global function, but I try to separate the problems).
I know of nothing standard for that.
If you want to stay in the language, you'll have to look at extensions as compilers have provided pragmas and attributes to control such things for a long time. In the case of gcc, asm labels seems designed for that problem. I've not used it and I've the a priori that it can't be used with templates excepted perhaps for explicit specializations.
The alternative is obviously playing with linker level tricks.
AFAIK a weak symbol doesn't make an object file providing it to be extracted from a static library if it is the only symbol provided by the object. You could arrange that the object file providing from C to your template provide also another unique symbol which is needed by the instantiation you want.
Linker scripts have a lot of power and if things haven't changed too much since the last time I took care of embedded systems (that's so long ago that they must changed, I just don't know if they have changed in that aspect) custom linker scripts are still pretty much mandatory in that field.

Order of function signature, call and definition

I want to ask order of function signature, call and definition
like, which one would the computer look first, second and third
So:
#include <iostream>
using namespace std;
void max(void);
void min(void);
int main() {
max();
min();
return;
}
void max() {
return;
}
void min() {
return;
}
So this is what I think,
the computer will go to main and look at the function call, then it will look at the
function signature, and at the last, it will look at the definition.
It is right?
Thank
It is right?
No.
You need to understand the difference between function declarations and function definitions, the difference between compilation, linking, and execution, and the difference between non-virtual and virtual functions.
Function declarations
This is a function declaration: void max(void);. It doesn't tell the compiler anything about what the function does. What it does is to tell the compiler how to call the function and how to interpret the result. When the compiler is compiling the body of some function, call it function A, the compiler doesn't need to know what other functions do. All it needs to know is what to do with the functions that function A calls. The compiler might generate code in assembly or some intermediate language that corresponds to your C++ function calls. Or it might reject your C++ code because your code doesn't make sense.
Determining whether your code makes sense is another key purpose of those function declarations. This is particularly important in C++ where multiple functions can have the same name. How would the compiler know which of the half dozen or so max functions to call if it didn't know about those functions? When your C++ code calls some function, the compiler must find one best match (possibly involving type conversions) with one of those function declarations. Your code doesn't make sense if the compiler can't find a match at all, or if it finds more than one match but can't distinguish one as the best match.
When the compiler does find a best match, the generated code will be in the form of a call to an undefined external reference to that function. Where that function lives is not the job of the compiler.
Function definitions
That void max(void) was a function declaration. The corresponding void max() {...} is the definition of that function. When the compiler is processing void max() {...} it doesn't have to worry about what other functions have called it. It just has to worry about processing void max() {...} . The body of this function becomes assembly or intermediate language code that is inserted into some compiled object file. The compiler marks the address of the entry point to this generated code is marked as such.
Compilation versus linking
So far I've talked about what the compiler does. It generates chunks of low-level code that correspond to your C++ code. That generated code is not ready for prime time because of those external references. Resolving those undefined external references is the job of the linker. The linker is what builds your executable from multiple object files, multiple libraries. It keeps track of where it has put those chunks of code in the executable. What about those undefined external references? If the linker has already placed that reference in the executable, the linker simply fills in the placeholder for that reference. If the linker hasn't come across the definition for that reference, it puts the reference and the placeholder onto a list of still-unresolved references. Every time the linker adds a chunk of code to the executable, it checks that list to see if it can fix any of those still-unresolved references. At the end, you will either have all references resolved or you will still have some outstanding ones. The latter is an error. The former means that you have an executable.
Execution
When your code runs, those function calls are really just some stack management wrapped around the machine language equivalent of that evil goto statement. There's no examining your function declarations; those don't even exist by the time the code is executed. Return? That's a goto also.
Non-virtual versus virtual functions
What I said above pertains to non-virtual functions. Run-time dispatching does occur for virtual functions. That run-time dispatching has nothing to do with examining function declarations. Those virtual functions are perhaps an issue for a different question.
One last thing:
Get out of the habit of using namespace std; Think of it as akin to smoking. It's a bad habit.
As you may know, the compiler converts the program into machine code (via several intermediate steps). Here is the dissassembly of the machine code for main() when compiled on Visual Studio 2012 in debug mode on Windows 8:
int main() {
00C24400 push ebp # Setup stack frame
00C24401 mov ebp,esp
00C24403 sub esp,0C0h
00C24409 push ebx
00C2440A push esi
00C2440B push edi
00C2440C lea edi,[ebp-0C0h] # Fill with guard bytes
00C24412 mov ecx,30h
00C24417 mov eax,0CCCCCCCCh
00C2441C rep stos dword ptr es:[edi]
max();
00C2441E call max (0C21302h) # Call max
min();
00C24423 call min (0C2126Ch) # Call min
return 0;
00C24428 xor eax,eax
}
00C2442A pop edi # Restore stack frame
00C2442B pop esi
00C2442C pop ebx
00C2442D add esp,0C0h
00C24433 cmp ebp,esp
}
00C24435 call __RTC_CheckEsp (0C212D5h) # Check for memory corruption
00C2443A mov esp,ebp
00C2443C pop ebp
00C2443D ret
The exact details will vary from compiler to compiler and operating system to operating system. If min() or max() had arguments or return values, they would be passed as appropriate for the architecture. The key point is that the compiler has already worked out what the arguments and return values are and created machine code that just passes or accepts them.
You can learn more details if you wish to help with debugging or to do low level calls but be aware that the machine code emitted can be highly variable. For example, here is the same code compiled on the same system in release mode (i.e. with optimizations on):
return 0;
01151270 xor eax,eax
}
01151272 ret
As you can see, it has detected that min() and max() do nothing and removed them completely. Since there is now no stack frame to setup and restore, that is gone, leaving a single instruction to set eax to 0 then returning (since the return value is in the eax register).