I have the following function that takes 3 double arguments. Inside my debugger when a break on this function is reached. Inspecting the arguments to the function I don't see the 3 double arguments.
On an x86 platform are double arguments to a function stored on the stack?
Below is the function and disassembly in windbg. Why don't I see the values passed in to the function as Args to Child in windbg?
vector<double> calculate_quadratic(double a, double b, double c)
{
double discriminant = (b * b) - 4 * a * c;
vector<double>result;
try
{
if (discriminant < 0)
throw Bad_Value{};
else
{
double d = sqrt(discriminant);
double px = (-b + d) / (2 * a);
double nx = (-b - d) / (2 * a);
result.push_back(px);
result.push_back(nx);
}
}
catch (Bad_Value)
{
cerr << "invalid value" << endl;
}
return result;
}
0:000> kb
# ChildEBP RetAddr Args to Child
00 003dfd2c 0126ad86 003dfe30 00000000 3ff00000 quadratic!calculate_quadratic
01 003dfe84 0126ba6e 00000001 0043d080 0043dd18 quadratic!main+0xc6
02 003dfe98 0126b8d0 ac1dec02 00000000 00000000 quadratic!invoke_main+0x1e
03 003dfef0 0126b76d 003dff00 0126ba88 003dff0c quadratic!__scrt_common_main_seh+0x150
04 003dfef8 0126ba88 003dff0c 772c336a 7efde000 quadratic!__scrt_common_main+0xd
05 003dff00 772c336a 7efde000 003dff4c 777f9f72 quadratic!mainCRTStartup+0x8
06 003dff0c 777f9f72 7efde000 77465726 00000000 kernel32!BaseThreadInitThunk+0xe
07 003dff4c 777f9f45 01261127 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70
08 003dff64 00000000 01261127 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> r
eax=003dfe30 ebx=003dfd48 ecx=acd07c23 edx=582e27d8 esi=003dfd50 edi=003dfd4c
eip=01268f70 esp=003dfd30 ebp=003dfe84 iopl=0 nv up ei pl nz ac po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000212
quadratic!calculate_quadratic:
01268f70 push ebp
0:000> dv /t /v
003dfd38 double a = 1
003dfd40 double b = -3
003dfd48 double c = 2
003dfd0c double discriminant = 1.7499487580265442e+127
003dfcf4 struct Vector<double> result = struct Vector<double>
Dumping the ChildEBP of the top frame I can now see the arguments on the stack in reverse order - In this case i used 10 three times which is represented as 4024000000000000
0:000> kb
# ChildEBP RetAddr Args to Child
00 004cfac4 0017ad86 004cfbc8 00000000 40240000 quadratic!calculate_quadratic
0:000> dd 004cfac4
004cfac4 5a23da80 0017ad86 004cfbc8 00000000
004cfad4 40240000 00000000 40240000 00000000
004cfae4 40240000 ed0a64cf 00000000 00000000
0:000> .formats 4024000000000000
Evaluate expression:
Hex: 40240000`00000000
Decimal: 4621819117588971520
Octal: 0400440000000000000000
Binary: 01000000 00100100 00000000 00000000 00000000 00000000 00000000 00000000
Chars: #$......
Time: Fri Dec 18 11:22:38.897 16246 (UTC - 5:00)
Float: low 0 high 2.5625
Double: 10
The default calling convention for C/C++ is cdecl. In this calling convention, when building for x86, arguments are passed on the stack in reverse order. Compiler options or function decorations can override this behaviour, of course.
Looking at your WinDBG output, the first three stack entries (args to child) are :
003dfe30 00000000 3ff00000
Since a double is 64 bits wide you're only looking at one and a half of your arguments. The first entry looks to be the contents of EAX...perhaps a compiler optimization has pushed EAX to the stack at the point your breakpoint hit? The next value is 00000000 3ff00000, which is LE of 3ff0000000000000 = 1(IEEE754), the leftmost argument and the last to be passed to the stack in cdecl.
How arguments are passed is compiler dependent and can often be changed by options or compiler directives.
Most x86 compilers will use either the x87 FPU stack (ST0-ST7 registers) or the SSE registers (XMM0-XMM7) if for passing floating point arguments. On MSVC, this is controlled by the /arch and /fp options.
Related
I'm trying to use c++ on an STM32 device compiling with gcc. The device loads the code and start executing it but hard faults on any member variable write.
I can see with GDB that member variables are stored at beginnning of memory (0x7 to be specific), of course the STM32 hard faults at the first write of that location.
I can see that BSS section is not generated unless i declare a variable in main (used readelf on the final elf file).
Shouldnt be member variables be placed in bss?
I'm compiling and linking with -nostdlib -mcpu=cortex-m0plus -fno-exceptions -O0 -g.
The linker script is:
ENTRY(start_of_memory);
MEMORY {
rom (rx) : ORIGIN = 0x08000000, LENGTH = 16K
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 2K
}
SECTIONS {
.text : {
*(.text)
} > rom
.data : {
*(.data)
*(.data.*)
} > ram
.bss : {
*(.bss)
*(.bss.*)
*(COMMON)
} > ram
}
The output of readelf (no variables declaration, only object usage):
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: ARM
Version: 0x1
Entry point address: 0x8000000
Start of program headers: 52 (bytes into file)
Start of section headers: 76536 (bytes into file)
Flags: 0x5000200, Version5 EABI, soft-float ABI
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 1
Size of section headers: 40 (bytes)
Number of section headers: 14
Section header string table index: 13
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 08000000 010000 0005a8 00 AX 0 0 4
[ 2] .rodata PROGBITS 080005a8 0105a8 00005c 00 A 0 0 4
[ 3] .ARM.attributes ARM_ATTRIBUTES 00000000 010604 00002d 00 0 0 1
[ 4] .comment PROGBITS 00000000 010631 000049 01 MS 0 0 1
[ 5] .debug_info PROGBITS 00000000 01067a 000a93 00 0 0 1
[ 6] .debug_abbrev PROGBITS 00000000 01110d 0003b8 00 0 0 1
[ 7] .debug_aranges PROGBITS 00000000 0114c5 000060 00 0 0 1
[ 8] .debug_line PROGBITS 00000000 011525 000580 00 0 0 1
[ 9] .debug_str PROGBITS 00000000 011aa5 000416 01 MS 0 0 1
[10] .debug_frame PROGBITS 00000000 011ebc 000228 00 0 0 4
[11] .symtab SYMTAB 00000000 0120e4 000640 10 12 86 4
[12] .strtab STRTAB 00000000 012724 000344 00 0 0 1
[13] .shstrtab STRTAB 00000000 012a68 00008f 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
y (purecode), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x010000 0x08000000 0x08000000 0x00604 0x00604 R E 0x10000
Section to Segment mapping:
Segment Sections...
00 .text .rodata
There is no dynamic section in this file.
There are no relocations in this file.
There are no unwind sections in this file.
Symbol table '.symtab' contains 100 entries:
Main (init platform probably does not use any variables):
int main(void) {
init_platform(SPEED_4_MHz);
gpio testpin(GPIO_A, 5);
testpin.dir(MODE_OUTPUT);
while (1) {
testpin.high();
wait();
testpin.low();
wait();
}
return 0;
}
Update #1:
The vector table is at beginning of memory, sp and msp are initialized successfully.
(gdb) p/x *0x00000000
$2 = 0x20000700
(gdb) p/x *0x00000004
$3 = 0x80000f1
(gdb) info registers
sp 0x20000700 0x20000700
lr 0xffffffff -1
pc 0x80000f6 0x80000f6 <main()+6>
xPSR 0xf1000000 -251658240
msp 0x20000700 0x20000700
psp 0xfffffffc 0xfffffffc
Putting a breakpoint on a constructor for the GPIO class, i can see variables are at 0x00000XXX
Breakpoint 2, gpio::gpio (this=0x7, port=0 '\000', pin=5 '\005') at gpio.cpp:25
25 mypin = pin;
(gdb) p/x &mypin
$6 = 0xb
I tried to make mypin a public member variable (was private), did not make any change.
Starting to think that dynamic allocation is needed with C++.
Address 0x7 is in the initial vector table in ROM, it is not writeable.
Unfortunately you don't have a section to populate the vector table, so this code is never going to work. You also don't appear to have a stack, which is where the members of gpio would be placed (because it is defined inside a function without the static keyword).
Start by taking the linker script provided as part of the STM32Cube package and then (if you must) modify it a little bit at a time until you break it. Then you will know what you have broken. It is not reasonable to write such a naïve linker script as this and expect it to work on a microcontroller.
of course the STM32 hard faults at the first write of that location.
STM32 does not "fault" if you try to write FLASH. It will simple have no effect.
You need to have a vector table in at the beginning of the FLASH memory. It has to contain as a minimum valid stack pointer address and the firmware entry point.
Your linker script and the code (I understand you do not use any STM supplied startup code) is far from being sufficient.
My advice:
Create the project using STM32Cube.
Then see how it should be done
Having this knowledge you can start to reinvent the wheel
The issue was in the launch script:
Not working:
toolchain\bin\arm-none-eabi-gdb.exe ^
-ex "target remote 127.0.0.1:3333" ^
-ex "load" ^
-ex "b main" ^
-ex "b unmanaged_isr_call" ^
-ex "b hard_fault_isr" ^
-ex "j main" binaries\main.elf
Working:
toolchain\bin\arm-none-eabi-gdb.exe ^
-ex "target remote 127.0.0.1:3333" ^
-ex "load" ^
-ex "b unmanaged_isr_call" ^
-ex "b hard_fault_isr" ^
-ex "set $pc = &main" binaries\main.elf
Made it work.
The issue was in j main.
The jump instruction does not modify the stack frame where all the object are placed by the compiler.
Using set $pc, execution starts at the given address, using jump execution starts at the first C line after the address, a big difference!.
From the gdb jump documentation:
The jump command does not change the current stack frame, or the stack pointer, or the contents of any memory location or any register other than the program counter. If locspec resolves to an address in a different function from the one currently executing, the results may be bizarre if the two functions expect different patterns of arguments or of local variables. For this reason, the jump command requests confirmation if the jump address is not in the function currently executing. However, even bizarre results are predictable if you are well acquainted with the machine-language code of your program.
The first lines make space in the stack for the objects "created" by main, space needed for the object to be used during execution. (verified by launching both commands and seeing differen msp values at the first C line).
With jump, those lines are not executed and the space is not allocated on stack: when code calls a funxction, the parameters will overwrite member data.
This is the strangest problem I have ever encountered. I am programming a chess engine and I have a function that returns a rank mask. For example, Consider this 64-bit bitboard.
00000000
00000000
00000000
00000000
00000100
00000000
00000000
00000000
The 1 in the middle is a piece.
Now my function should return
00000000
00000000
00000000
00000000
11111111
00000000
00000000
00000000
Very simple, just return a mask of the rank. Here is my code
uint64_t get_rank_mask(int sq)
{
return (0xFF<<(sq-(sq%8)));
}
Here is what the function returns when I pass 36, or the square e5
00000000
00000000
00000000
00000000
00000000
00000000
00000000
11111111
Hmm, strange it is. Let me make a small change in the code.
uint64_t get_rank_mask(int sq)
{
uint64_t mask = 0xFF;
mask<<=(sq-(sq%8));
return mask;
}
Here is the return value now
00000000
00000000
00000000
11111111
00000000
00000000
00000000
00000000
And magically, that is the intended result. I don't even know the difference between the two code samples. Can anyone explain this behaviour?
0xFF is an int. Assuming an int has 32 bits, shifting this value left by 32 will invoke undefined behavior.
In the second version, you are storing 0xFF in an unsigned integral type. This can be shifted any number of bits, and that operation is well defined. In your case, you are storing it in an unsigned int with 64 bits, and so shifting left by 32 gives the result you want.
The stack frame pointer (EBP) should always point to where the previous stack frame was right but why is that not the case in my application! That would indicate something is really wrong..hard to believe!
I created multiple simple demo applications where the stack pointer always points to the previous stack frame but I can't make sense of why this is not the case in this application and it is happening when my application is just starting up!
The following is my call stack
0:000> k
# ChildEBP RetAddr
00 0018fee4 6381d1cd acn!CAcnApp::InitInstance+0x41 [c:\acn-project\acn\acn.cpp # 527]
01 0018fef4 00428575 MFC80U!AfxWinMain+0x48 [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\winmain.cpp # 37]
02 0018ff88 765d336a acn!__tmainCRTStartup+0x150 [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c # 589]
03 0018ff94 76f59902 kernel32!BaseThreadInitThunk+0xe
04 0018ffd4 76f598d5 ntdll!__RtlUserThreadStart+0x70
05 0018ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> dc 0018fee4
0018fee4 ffffffff 6381d1cd 00489498 00000001 .......c..H.....
0018fef4 00000000 00428575 00400000 00000000 ....u.B...#.....
0018ff04 01e53fd2 0000000a 87b8aee0 00000000 .?..............
0018ff14 00000000 7efde000 00000044 01e54012 .......~D....#..
0018ff24 01e53ff2 01e53fd4 00000000 00000000 .?...?..........
0018ff34 00000000 00000000 00000000 00000000 ................
0018ff44 00000000 00000000 00000000 00000000 ................
0018ff54 00000000 00000000 0018ff84 00428e5d ............].B.
0:000> dc 0018fef4
0018fef4 00000000 00428575 00400000 00000000 ....u.B...#.....
0018ff04 01e53fd2 0000000a 87b8aee0 00000000 .?..............
0018ff14 00000000 7efde000 00000044 01e54012 .......~D....#..
0018ff24 01e53ff2 01e53fd4 00000000 00000000 .?...?..........
0018ff34 00000000 00000000 00000000 00000000 ................
0018ff44 00000000 00000000 00000000 00000000 ................
0018ff54 00000000 00000000 0018ff84 00428e5d ............].B.
0018ff64 01e53fd2 00000000 00000000 0018ff0c .?..............
0:000> dc 0018ff88
0018ff88 0018ff94 765d336a 7efde000 0018ffd4 ....j3]v...~....
0018ff98 76f59902 7efde000 7d7a657d 00000000 ...v...~}ez}....
0018ffa8 00000000 7efde000 00000000 00000000 .......~........
0018ffb8 00000000 0018ffa0 00000000 ffffffff ................
0018ffc8 76f958c5 0b965c89 00000000 0018ffec .X.v.\..........
0018ffd8 76f598d5 0042873d 7efde000 00000000 ...v=.B....~....
0018ffe8 00000000 00000000 00000000 0042873d ............=.B.
0018fff8 7efde000 00000000 78746341 00000020 ...~....Actx ...
The control is in the first line of InitInstance() so it's like my application is drawing its first breath and the stack seems to be already corrupted? Well the app class constructor comes before this but I checked the call stack is in similar state there as well.
Notice the stack frame pointer (EFP) check for both 1st and 2nd frame fails but the stack is good beyond that.
My first question is that is there any explanation the call stack can be like this and this being Ok? In other words, can we say the call stack is definitely broken? The application does load and calls various dlls if that may play any part (don't know why it would though).
What could be the suspect in this case since the application has only barely started!?
Update (code)
Here is constructor which is very simple. And as for InitInstance(), that function is very long but my breakpoint is on first line so its code is never executed when call stack is like that.
CAcnApp::CAcnApp()
{
m_bServMode = FALSE;
m_bFactory = FALSE;
m_bDownload = FALSE;
m_pEngine = NULL;
m_hWiztomMod = NULL;
m_pServer = new CAcnServer;
}
Second update
I posted a follow up question to share extra information after further investigation and that does qualify as separate question due to differences.
BTW, global or file global objects are created before the main function is called.
If an object's constructor has problems, you could see any number of defects occurring before main is called.
Review your object's constructors. You should be able to set a breakpoint in the object's constructor.
Edit 1: Memory allocation in constructor
Having a global object that has dynamic memory allocation may cause problems. The object requires that the dynamic memory allocation is initialized before the object is constructed. Try commenting out the dynamic memory allocation and see if the issue goes away.
A workaround is to create an "initialize" method that can be called after the main entry point is reached. The initialize method would perform dynamic memory allocation.
I would like to overwrite function (interupt handlers) with the weak attribute, but linker does not link my definition. Codes are shorted for better reading.
vectors.c
void NMI_Handler (void) __attribute__((weak));
void HardFault_Handler (void) __attribute__((weak));
__attribute__ ((section(".vectors"), used))
void (* const gVectors[])(void) =
{
NMI_Handler,
HardFault_Handler
};
void NMI_Handler (void) { while(1); }
void HardFault_Handler (void) { while(1); }
I redefine default definition in the file cpuexcept.cpp
extern "C" __attribute__((naked))
void NMI_Handler()
{
EXCEPT_ENTRY(CPUExcept);
}
extern "C" __attribute__((naked))
void HardFault_Handler()
{
EXCEPT_ENTRY(CPUExcept);
}
If I compile and dump it, output (library lib.a) is:
cpuexcept.oo: file format elf32-littlearm
rw-rw-rw- 0/0 4728 Jun 26 16:20 2012 cpuexcept.oo
architecture: arm, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x00000000
private flags = 5000000: [Version5 EABI]
Sections:
Idx Name Size VMA LMA File off Algn Flags
0 .text 0000051c 00000000 00000000 00000034 2**2 CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000000 00000000 00000000 00000550 2**0 CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000550 2**0 ALLOC
3 .rodata 000001dc 00000000 00000000 00000550 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .comment 00000012 00000000 00000000 0000072c 2**0 CONTENTS, READONLY
5 .ARM.attributes 00000031 00000000 00000000 0000073e 2**0 CONTENTS, READONLY
SYMBOL TABLE:
00000000 l df *ABS* 00000000 cpuexcept.cpp
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
000004e0 g F .text 0000000a NMI_Handler
000004ec g F .text 0000000a HardFault_Handler
000004e0 <NMI_Handler>:
4e0: e92d 0ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp}
4e4: 4668 mov r0, sp
4e6: f7ff fffe bl c0 <CPUExcept> 4e6: R_ARM_THM_CALL CPUExcept
4ea: bf00 nop
000004ec <HardFault_Handler>:
4ec: e92d 0ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp}
4f0: 4668 mov r0, sp
4f2: f7ff fffe bl c0 <CPUExcept> 4f2: R_ARM_THM_CALL CPUExcept
4f6: bf00 nop
vectors.o: file format elf32-littlearm
rw-rw-rw- 0/0 4464 Jun 27 13:52 2012 vectors.o
architecture: arm, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x00000000
private flags = 5000000: [Version5 EABI]
Sections:
Idx Name Size VMA LMA File off Algn Flags
0 .text 00000114 00000000 00000000 00000034 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000000 00000000 00000000 00000148 2**0 CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000148 2**0 ALLOC
3 .vectors 00000130 00000000 00000000 00000148 2**2 CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
4 .comment 00000012 00000000 00000000 00000278 2**0 CONTENTS, READONLY
5 .ARM.attributes 00000031 00000000 00000000 0000028a 2**0 CONTENTS, READONLY
SYMBOL TABLE:
00000000 l df *ABS* 00000000 vectors.c
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .vectors 00000000 .vectors
00000000 l d .comment 00000000 .comment
00000000 l d .ARM.attributes 00000000 .ARM.attributes
00000000 w F .text 00000002 NMI_Handler
00000004 w F .text 00000002 HardFault_Handler
00000000 <NMI_Handler>:
0: e7fe b.n 0 <NMI_Handler>
2: bf00 nop
00000004 <HardFault_Handler>:
4: e7fe b.n 4 <HardFault_Handler>
6: bf00 nop
Default function with the weak attribute is linked in to target application. My definition is linked correct, if I define function f() in cpuexcept.cpp and I use it in main function or if my definiton of handler is in other .c module.
I use arm-none-eabi-gcc 4.6.2 (YAGARTO) compiler in cygwin.
You could try to define your function like
void NMI_Handler(void)
and not as
void NMI_Handler()
As the weak definition is also void NMI_Handler (void) __attribute__((weak));
So the linker will not see any difference.
I have a corruption memory heap problem with an application.
by using windbg and a dump file of the crash as an input I have the following output with dd esp command
0:002> dd esp
00000000`03e3e490 14badf55 00000000 03e3e8c0 00000000
00000000`03e3e4a0 00000000 00000000 03e3e8c0 00000000
00000000`03e3e4b0 03e3e8c0 00000000 6b0064f2 00000000
00000000`03e3e4c0 03e3f030 00000000 6b002510 00000000
00000000`03e3e4d0 00000000 00000000 03dfede8 00000000
00000000`03e3e4e0 c0000005 00000000 00000000 7d6210e8
00000000`03e3e4f0 00000002 00000000 00000000 00000000
00000000`03e3e500 00000000 00001000 78b83980 036b0000
There is this adress : 14badf55
I really don't know how to interpret this "bad"..
Is anyone have an idea of the meaning of this bad ?
EDIT:
when I try to use this command :
u 14badf55
the following output comes :
00000000`14badf55 ?? ???
^ Memory access error in 'u 14badf55'
The .ecxr command give me :
rax=0000000003e3e488 rbx=0000000003e3e8c0 rcx=0000000003e3dfb0
rdx=0000000000000000 rsi=000000006b005a17 rdi=0000000000000000
rip=000000006b006369 rsp=0000000003e3e490 rbp=0000000003dfede8
r8=000000006b00254a r9=0000000003e3e4d8 r10=0000000000000007
r11=0000000000000000 r12=000000006b01fe90 r13=0000000000000000
r14=0000000003e3f110 r15=0000000078b83980
iopl=0 nv up ei pl nz na po nc
cs=0033 ss=002b ds=0000 es=0000 fs=0000 gs=0000 efl=00000204
wow64!Wow64NotifyDebugger+0x9:
00000000`6b006369 b001 mov al,1
You can see the c0000005 output in the file. This is the sign of a access violation.
Run the following:
- .cxr 00000000`03e3e4e0 (To set the exception context)
- kL (to get a stack trace)