I am assembly-stepping and something weird is happening.
I have two separate flash blocks and they both contain code. Because they are so far apart, function calls from one block to the other requires an intermediate jump aka veneer
which is automatically generated by the linker.
This has worked up until now and I did something - no idea what - to break it.
0x1001a9ca: 0x0cf0c5fe bl 0x10027758 <__atiupy_PutOutput2_veneer>
After that is executed, the PC is 0x100275ce
which is wrong .
If I scroll in the disassembly window to 0x10027758
, I see the label __atiupy_PutOutput2_veneer
.
Why is it jumping to wrong address?
UPDATE
It's jumping from C-code to C++ code. Yes I have extern "C"
in the .h
for the functions in C++ code called from C code.
C compile options are: -xc -Wall -Werror -std=c99 -nostdlib -mthumb -mtune=cortex-m4 -mlittle-endian -Wdouble-promotion -DNDEBUG -fdata-sections -ffunction-sections -c -save-temps=obj -g3 -gdwarf-2
C++ compile options are: -mthumb -mlittle-endian -x c++ -gdwarf-2 -g3 -fomit-frame-pointer -fnothrow-opt -ffreestanding -fverbose-asm -std=c++11 -c -fno-rtti -ffunction-sections -fdata-sections -fno-exceptions
By request, some disassembly using objdump -d
.
Where it's about to jump to 0x10027758
(but never gets there)
1001a9bc <mp_hal_stdout_tx_strn_cooked>:
1001a9bc: b580 push {r7, lr}
1001a9be: b082 sub sp, #8
1001a9c0: af00 add r7, sp, #0
1001a9c2: 6078 str r0, [r7, #4]
1001a9c4: 6039 str r1, [r7, #0]
1001a9c6: 6878 ldr r0, [r7, #4]
1001a9c8: 6839 ldr r1, [r7, #0]
1001a9ca: f00c fec5 bl 10027758 <__atiupy_PutOutput2_veneer>
1001a9ce: f107 0708 add.w r7, r7, #8
1001a9d2: 46bd mov sp, r7
1001a9d4: bd80 pop {r7, pc}
1001a9d6: bf00 nop
Where it should jump to
10027758 <__atiupy_PutOutput2_veneer>:
10027758: b401 push {r0}
1002775a: 4802 ldr r0, [pc, #8] ; (10027764 <__atiupy_PutOutput2_veneer+0xc>)
1002775c: 4684 mov ip, r0
1002775e: bc01 pop {r0}
10027760: 4760 bx ip
10027762: bf00 nop
10027764: 00035abd .word 0x00035abd
It actually jumps to 0x100275ce
but I'm pasting the entire function located here
100275c8 <___ZN21CKinetisI2CController7DisableEv_veneer>:
100275c8: b401 push {r0}
100275ca: 4802 ldr r0, [pc, #8] ; (100275d4 <___ZN21CKinetisI2CController7DisableEv_veneer+0xc>)
100275cc: 4684 mov ip, r0
100275ce: bc01 pop {r0}
100275d0: 4760 bx ip
100275d2: bf00 nop
100275d4: 00029b2d .word 0x00029b2d
I set a breakpoint at mp_hal_stdout_tx_strn_cooked
and then assembly-stepped using stepi
p/x $pc
$2 = 0x1001a9c6
disass
Dump of assembler code for function mp_hal_stdout_tx_strn_cooked:
0x1001a9bc <+0>: push {r7, lr}
0x1001a9be <+2>: sub sp, #8
0x1001a9c0 <+4>: add r7, sp, #0
0x1001a9c2 <+6>: str r0, [r7, #4]
0x1001a9c4 <+8>: str r1, [r7, #0]
=> 0x1001a9c6 <+10>: ldr r0, [r7, #4]
0x1001a9c8 <+12>: ldr r1, [r7, #0]
0x1001a9ca <+14>: bl 0x10027758 <__atiupy_PutOutput2_veneer>
0x1001a9ce <+18>: add.w r7, r7, #8
0x1001a9d2 <+22>: mov sp, r7
0x1001a9d4 <+24>: pop {r7, pc}
End of assembler dump.
stepi
stepi
0x1001a9c8 23 atiupy_PutOutput2(str, len);
disass
Dump of assembler code for function mp_hal_stdout_tx_strn_cooked:
0x1001a9bc <+0>: push {r7, lr}
0x1001a9be <+2>: sub sp, #8
0x1001a9c0 <+4>: add r7, sp, #0
0x1001a9c2 <+6>: str r0, [r7, #4]
0x1001a9c4 <+8>: str r1, [r7, #0]
0x1001a9c6 <+10>: ldr r0, [r7, #4]
=> 0x1001a9c8 <+12>: ldr r1, [r7, #0]
0x1001a9ca <+14>: bl 0x10027758 <__atiupy_PutOutput2_veneer>
0x1001a9ce <+18>: add.w r7, r7, #8
0x1001a9d2 <+22>: mov sp, r7
0x1001a9d4 <+24>: pop {r7, pc}
End of assembler dump.
stepi
stepi
0x1001a9ca 23 atiupy_PutOutput2(str, len);
diasass
Undefined command: "diasass". Try "help".
disass
Dump of assembler code for function mp_hal_stdout_tx_strn_cooked:
0x1001a9bc <+0>: push {r7, lr}
0x1001a9be <+2>: sub sp, #8
0x1001a9c0 <+4>: add r7, sp, #0
0x1001a9c2 <+6>: str r0, [r7, #4]
0x1001a9c4 <+8>: str r1, [r7, #0]
0x1001a9c6 <+10>: ldr r0, [r7, #4]
0x1001a9c8 <+12>: ldr r1, [r7, #0]
=> 0x1001a9ca <+14>: bl 0x10027758 <__atiupy_PutOutput2_veneer>
0x1001a9ce <+18>: add.w r7, r7, #8
0x1001a9d2 <+22>: mov sp, r7
0x1001a9d4 <+24>: pop {r7, pc}
End of assembler dump.
stepi
stepi
0x100275ce in ___ZN21CKinetisI2CController7DisableEv_veneer ()
disass
Dump of assembler code for function ___ZN21CKinetisI2CController7DisableEv_veneer:
0x100275c8 <+0>: push {r0}
0x100275ca <+2>: ldr r0, [pc, #8] ; (0x100275d4 <___ZN21CKinetisI2CController7DisableEv_veneer+12>)
0x100275cc <+4>: mov r12, r0
=> 0x100275ce <+6>: pop {r0}
0x100275d0 <+8>: bx r12
0x100275d2 <+10>: nop
0x100275d4 <+12>: ldr r3, [sp, #180] ; 0xb4
0x100275d6 <+14>: movs r2, r0
End of assembler dump.
stepi
stepi
0x100275d0 in ___ZN21CKinetisI2CController7DisableEv_veneer ()
disass
Dump of assembler code for function ___ZN21CKinetisI2CController7DisableEv_veneer:
0x100275c8 <+0>: push {r0}
0x100275ca <+2>: ldr r0, [pc, #8] ; (0x100275d4 <___ZN21CKinetisI2CController7DisableEv_veneer+12>)
0x100275cc <+4>: mov r12, r0
0x100275ce <+6>: pop {r0}
=> 0x100275d0 <+8>: bx r12
0x100275d2 <+10>: nop
0x100275d4 <+12>: ldr r3, [sp, #180] ; 0xb4
0x100275d6 <+14>: movs r2, r0
End of assembler dump.
Assembly file before compilation
Someone wanted the assembly file output from the compiler, rather than objdump
's interpretation. This output is a result of the compile option -save-temps=obj
.LFE14:
.size mp_hal_stdout_tx_strn, .-mp_hal_stdout_tx_strn
.section .text.mp_hal_stdout_tx_strn_cooked,"ax",%progbits
.align 2
.global mp_hal_stdout_tx_strn_cooked
.thumb
.thumb_func
.type mp_hal_stdout_tx_strn_cooked, %function
mp_hal_stdout_tx_strn_cooked:
.LFB15:
.loc 1 22 0
.cfi_startproc
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 1, uses_anonymous_args = 0
push {r7, lr}
.LCFI11:
.cfi_def_cfa_offset 8
.cfi_offset 7, -8
.cfi_offset 14, -4
sub sp, sp, #8
.LCFI12:
.cfi_def_cfa_offset 16
add r7, sp, #0
.LCFI13:
.cfi_def_cfa_register 7
str r0, [r7, #4]
str r1, [r7, #0]
.loc 1 23 0
ldr r0, [r7, #4]
ldr r1, [r7, #0]
bl atiupy_PutOutput2
.loc 1 25 0
add r7, r7, #8
mov sp, r7
pop {r7, pc}
.cfi_endproc
(Sad) update
I created the minimal example but the issue doesn't occur. Therefore, I think it's something in my environment. I will start reverting local changes and will update. I wouldn't call the below code complete because you'd need the linker file but since it doesn't reproduce the issue, I don't see a point in providing everything.
main.cpp
#include "common.h"
int main()
{
test1();
}
int main_test()
{
int a = 5;
a = 23424 * a;
return a;
}
test.c
#include "common.h"
void test1()
{
int a;
a = main_test();
a *= 2;
}
common.h
#ifdef __cplusplus
extern "C" {
#endif //#ifdef __cplusplus
int main_test();
void test1();
#ifdef __cplusplus
}
#endif //#ifdef __cplusplus
main.obj is placed in "lower" flash block while test.obj is in upper block. When jumping from upper to lower, the PC correctly jumps to the right address for veneer
.
SOLVED: a power-cycle fixed it. Must have been electrical issue with the upper flash block that caused the HW execution unit to read wrong value from flash.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.