I have some stack dump, an elf with debug symbols as well as the original source code. Since this code runs in an embedded environment, and we cannot connect JTAG, the only information we have is the stack dump which is produced by the hard fault handler. I'm trying to reconstruct the callstack from the dump, but something here doesn't add up. Code is running on ARM Cortex M4.
The real callstack:
Example of a crashing function
time_t calcCurrentTime(void) ->
uint32_t calcDiff(void) ->
void voidFunction(void) ->
void voidFunctionWith1Param(int param) ->
int intFunction(void) ->
int intFunctionWithParam(int param) ->
void crashingFunction(void) ->
(*nullPtrFunction)(void)()
The stack:
On the left, the stack address, on the right the value at that address.
0xc0e1fe8 0x0000002b, r0
0xc0e1fec 0x0000000a, r1
0xc0e1ff0 0x00026390, r2
0xc0e1ff4 0x00000000, r3
0xc0e1ff8 0x77dd6416, r12
0xc0e1ffc 0x18e1877b, lr
0xc0e2000 0x00000000, pc
0xc0e2004 0x60000000, xpsr
0xc0e2008 0x12000000
0xc0e200c 0x18e18793, lr to crashingFunction
0xc0e2010 0x0000014e
0xc0e2014 0x18e187ab, lr to intFunctionWithParam
0xc0e2018 0x12000000
0xc0e201c 0x18e187c1, lr to intFunction
0xc0e2020 0x12000000
0xc0e2024 0x18e187e3, lr to voidFunctionWith1Param
0xc0e2028 0x00000000
0xc0e202c 0x18e18811, lr to voidFunction
0xc0e2030 0x00000000
0xc0e2034 0x00022d68
0xc0e2038 0x00000000
0xc0e203c 0x18e18837, lr to calcDiff
0xc0e2040 0x00000000
0xc0e2044 0x18e4f899
0xc0e2048 0x00022d68
0xc0e204c 0x00000000
0xc0e2050 0x18e6b00c
0xc0e2054 0x00022d68
0xc0e2058 0x18e0f529, lr to whoever called calcCurrentTime
...
The assembly:
======== void __stdcall crashingFunction(void) ========
18e18768 08 b5 push { r3, lr }
18e1876a 04 48 ldr r0, "Entered crashingFunction\r\n"
18e1876c 44 f0 58 f8 bl iprintf
18e18770 03 48 ldr r0, "About to execute crashing func\r\n"
18e18772 44 f0 55 f8 bl iprintf
18e18776 00 23 movs r3,#0x0
18e18778 98 47 blx r3
18e1877a 08 bd pop { r3, pc }
======== int __stdcall intFunctionWithParam(int param) ========
18e18784 10 b5 push { r4, lr }
18e18786 04 46 mov r4,r0
18e18788 03 48 ldr r0, "Entered intFunctionWithParam\r\n"
18e1878a 44 f0 49 f8 bl iprintf
18e1878e ff f7 eb ff bl crashingFunction
18e18792 60 1d adds r0,r4,#0x5
18e18794 10 bd pop { r4, pc }
======== int __stdcall intFunction(void) ========
18e1879c 10 b5 push { r4, lr }
18e1879e 84 b0 sub sp,#0x10
18e187a0 0d 48 ldr r0, "Entered intFunction\r\n"
18e187a2 44 f0 3d f8 bl iprintf
18e187a6 02 23 movs r3,#0x2
18e187a8 01 93 str r3,[sp,#arr[0]]
18e187aa 05 23 movs r3,#0x5
18e187ac 02 93 str r3,[sp,#arr[1]]
18e187ae 01 20 movs r0,#0x1
18e187b0 ff f7 e8 ff bl intFunctionWithParam
18e187b4 03 90 str r0,[sp,#arr[2]]
18e187b6 00 24 movs r4,#0x0
18e187b8 08 e0 b loopEnd
loopStart:
18e187ba 04 ab add r3,sp,#0x10
18e187bc 03 eb 84 03 add.w r3,r3,r4, lsl #0x2
18e187c0 53 f8 0c 1c ldr.w r1,[r3,#-0xc]
18e187c4 05 48 ldr r0, "Got value: %d"
18e187c6 44 f0 2b f8 bl iprintf
18e187ca 01 34 adds r4,#0x1
loopEnd:
18e187cc 02 2c cmp r4,#0x2
18e187ce f4 dd ble loopStart
18e187d0 0a 20 movs r0,#0xa
18e187d2 04 b0 add sp,#0x10
18e187d4 10 bd pop { r4, pc }
======== void __stdcall voidFunctionWith1Param(int param) ========
18e187e0 08 b5 push { r3, lr }
18e187e2 05 48 ldr r0, "Entered voidFunctionWith1Param\r\n"
18e187e4 44 f0 1c f8 bl iprintf
18e187e8 ff f7 d8 ff bl intFunction
18e187ec 01 46 mov r1,r0
18e187ee 03 48 ldr r0, "Result from a is %d\r\n"
18e187f0 44 f0 16 f8 bl iprintf
18e187f4 08 bd pop { r3, pc }
======== void __stdcall voidFunction(void) ========
18e18800 push { r3, lr }
18e18802 ldr r0, "Entered voidFunction\r\n"
18e18804 bl iprintf
18e18808 movs r0,#0x1
18e1880a bl voidFunctionWith1Param
18e1880e ldr r0, "Done!"
18e18810 bl iprintf
18e18814 pop { r3, pc }
======== uint __stdcall calcDiff(void) ========
18e18820 38 b5 push { r3, r4, r5, lr }
18e18822 e8 f7 e7 ff bl notRelatedFunc ; Saves milliseconds to r3
18e18826 0a 4d ldr r5,[0x18e18850] ; r5 = 1000
18e18828 a5 fb 00 30 umull r3,r0,r5,r0
18e1882c 84 09 lsrs r4,r0,#0x6 ; miliseconds / 1000
18e1882e 09 4b ldr r3,[0x18e18854]
18e18830 18 68 ldr r0,[r3,#0x0] ; globalVariable
18e18832 a5 fb 00 30 umull r3,r0,r5,r0
18e18836 85 09 lsrs r5,r0,#0x6 ; globalVariable / 1000
18e18838 ff f7 e2 ff bl voidFunction
18e1883c ac 42 cmp r4,r5
18e1883e 05 d8 bhi notRelatedFunc2
...
The questions:
LR to calcCurrentTime was lost. How is this possible?
To get to the next LR from 0xc0e202c we had to add 16, not 8. Despite voidFunction being the most unremarkable function of the bunch. It has no variables defined on the stack. So why is there such a gap in the stack?
I'm trying to figure out the rules in order to manually unwind the call stack.
Thank you.
Related
This question already has answers here:
Why does clang produce inefficient asm with -O0 (for this simple floating point sum)?
(1 answer)
Calling printf from aarch64 asm code on Apple M1 / MacOS
(1 answer)
Unoptimized clang++ code generates unneeded "movl $0, -4(%rbp)" in a trivial main()
(1 answer)
How to remove "noise" from GCC/clang assembly output?
(3 answers)
Closed 14 days ago.
I am new to learning about assembly and find it very interesting. I am trying to dissect what the purpose of setting registers x8 and x9 are in this example. Specifically, I am unsure as to why x8 and x9 are set at all if the printf function relies on registers x0 - x7 for the input it needs, and that we don't need to access the values saved in x8 and x9 later on anyway. I am guessing it maybe has to do with the fact that printf might manipulate the values in the input registers in some way that we would need to preserve the values in x8 / 9 if we were to need them later on (which we don't, but...). Printf just seems sort of like a black-box to me and results in assembly code that I don't see when I call user-defined functions (ie, I have yet to see x8 and x9 used when I call other functions that I wrote in my C program). Any help would be greatly appreciated, thank you!
output: file format mach-o arm64
Disassembly of section __TEXT,__text:
0000000100003f48 <_main>:
100003f48: ff c3 00 d1 sub sp, sp, #48
100003f4c: fd 7b 02 a9 stp x29, x30, [sp, #32]
100003f50: fd 83 00 91 add x29, sp, #32
100003f54: 08 00 80 52 mov w8, #0
100003f58: a8 43 1f b8 stur w8, [x29, #-12]
100003f5c: bf c3 1f b8 stur wzr, [x29, #-4]
100003f60: a8 00 80 52 mov w8, #5
100003f64: a8 83 1f b8 stur w8, [x29, #-8]
100003f68: a9 83 5f b8 ldur w9, [x29, #-8]
100003f6c: e8 03 09 aa mov x8, x9
100003f70: e9 03 00 91 mov x9, sp
100003f74: 28 01 00 f9 str x8, [x9]
100003f78: 00 00 00 90 adrp x0, 0x100003000 <_main+0x30>
100003f7c: 00 b0 3e 91 add x0, x0, #4012
100003f80: 08 00 00 94 bl 0x100003fa0 <_printf+0x100003fa0>
100003f84: a0 43 5f b8 ldur w0, [x29, #-12]
100003f88: a8 83 5f b8 ldur w8, [x29, #-8]
100003f8c: 08 05 00 11 add w8, w8, #1
100003f90: a8 83 1f b8 stur w8, [x29, #-8]
100003f94: fd 7b 42 a9 ldp x29, x30, [sp, #32]
100003f98: ff c3 00 91 add sp, sp, #48
100003f9c: c0 03 5f d6 ret
Disassembly of section __TEXT,__stubs:
0000000100003fa0 <__stubs>:
100003fa0: 10 00 00 b0 adrp x16, 0x100004000 <__stubs+0x4>
100003fa4: 10 02 40 f9 ldr x16, [x16]
100003fa8: 00 02 1f d6 br x16
This is the C code that was used to generate the above snippet:
#include <stdio.h>
int main()
{
int x = 5;
printf("x is %d\n", x);
return 0;
}
I've been trying to develop a small OS and managed to switch into protected mode, in order to write C code instead of assembly, but since this means I can't use interrupt 10h anymore, I have to write chars to the video memory address. So I tried creating a new print function to easily print out whole strings instead of printing each char separately. That's where the problems came in, for some reason, while printing single chars with the printchar function works, this new print function doesn't work, no matter what I try.
Here's my C Code:
void print(char* message, int offset);
void printChar(char character, int offset);
void start() {
printChar('M', 2);
print("Test String", 4);
while (1) {
}
}
void print(char* msg, int offset) {
for (int i = 0; msg[i] != '\0'; i++)
{
printChar(msg[i], (i * 2) + offset);
}
}
void printChar(char character, int offset) {
unsigned char* vidmem = (unsigned char*)0xB8000;
*(vidmem + offset + 1) = character;
*(vidmem + offset + 2) = 0x0f;
}
I then use these commands to convert my code to binary and put it onto the second sector of a floppy disk with sectedit.
gcc -c test.c
objcopy -O binary -j .text test.o test.bin
Also here's the assembly code generated, when using objdump -d test.o
0000000000000000 <start>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 20 sub $0x20,%rsp
8: ba 02 00 00 00 mov $0x2,%edx
d: b9 4d 00 00 00 mov $0x4d,%ecx
12: e8 73 00 00 00 call 8a <printChar>
17: ba 04 00 00 00 mov $0x4,%edx
1c: 48 8d 05 00 00 00 00 lea 0x0(%rip),%rax # 23 <start+0x23>
23: 48 89 c1 mov %rax,%rcx
26: e8 02 00 00 00 call 2d <print>
2b: eb fe jmp 2b <start+0x2b>
000000000000002d <print>:
2d: 55 push %rbp
2e: 48 89 e5 mov %rsp,%rbp
31: 48 83 ec 30 sub $0x30,%rsp
35: 48 89 4d 10 mov %rcx,0x10(%rbp)
39: 89 55 18 mov %edx,0x18(%rbp)
3c: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
43: eb 29 jmp 6e <print+0x41>
45: 8b 45 fc mov -0x4(%rbp),%eax
48: 8d 14 00 lea (%rax,%rax,1),%edx
4b: 8b 45 18 mov 0x18(%rbp),%eax
4e: 01 c2 add %eax,%edx
50: 8b 45 fc mov -0x4(%rbp),%eax
53: 48 63 c8 movslq %eax,%rcx
56: 48 8b 45 10 mov 0x10(%rbp),%rax
5a: 48 01 c8 add %rcx,%rax
5d: 0f b6 00 movzbl (%rax),%eax
60: 0f be c0 movsbl %al,%eax
63: 89 c1 mov %eax,%ecx
65: e8 20 00 00 00 call 8a <printChar>
6a: 83 45 fc 01 addl $0x1,-0x4(%rbp)
6e: 8b 45 fc mov -0x4(%rbp),%eax
71: 48 63 d0 movslq %eax,%rdx
74: 48 8b 45 10 mov 0x10(%rbp),%rax
78: 48 01 d0 add %rdx,%rax
7b: 0f b6 00 movzbl (%rax),%eax
7e: 84 c0 test %al,%al
80: 75 c3 jne 45 <print+0x18>
82: 90 nop
83: 90 nop
84: 48 83 c4 30 add $0x30,%rsp
88: 5d pop %rbp
89: c3 ret
000000000000008a <printChar>:
8a: 55 push %rbp
8b: 48 89 e5 mov %rsp,%rbp
8e: 48 83 ec 10 sub $0x10,%rsp
92: 89 c8 mov %ecx,%eax
94: 89 55 18 mov %edx,0x18(%rbp)
97: 88 45 10 mov %al,0x10(%rbp)
9a: 48 c7 45 f8 00 80 0b movq $0xb8000,-0x8(%rbp)
a1: 00
a2: 8b 45 18 mov 0x18(%rbp),%eax
a5: 48 98 cltq
a7: 48 8d 50 01 lea 0x1(%rax),%rdx
ab: 48 8b 45 f8 mov -0x8(%rbp),%rax
af: 48 01 c2 add %rax,%rdx
b2: 0f b6 45 10 movzbl 0x10(%rbp),%eax
b6: 88 02 mov %al,(%rdx)
b8: 8b 45 18 mov 0x18(%rbp),%eax
bb: 48 98 cltq
bd: 48 8d 50 02 lea 0x2(%rax),%rdx
c1: 48 8b 45 f8 mov -0x8(%rbp),%rax
c5: 48 01 d0 add %rdx,%rax
c8: c6 00 0f movb $0xf,(%rax)
cb: 90 nop
cc: 48 83 c4 10 add $0x10,%rsp
d0: 5d pop %rbp
d1: c3 ret
d2: 90 nop
d3: 90 nop
d4: 90 nop
d5: 90 nop
d6: 90 nop
d7: 90 nop
d8: 90 nop
d9: 90 nop
da: 90 nop
db: 90 nop
dc: 90 nop
dd: 90 nop
de: 90 nop
df: 90 nop
edit: The problem basically lied in me not doing this on a linux distribution, with all the things I'd need to do to do it in Windows not properly set up, huge thanks to MichaelPetch who explained the problems to me, I've now switched to a linux VM and after slightly correcting the code, it works (as the comments pointed out my offset was weird, I used that offset as it worked in the broken setup I had, but normally it shouldn't).
I apologize in advance if my question isn't formatted in the best way, I'm new to asking questions here.
I've been interested in learning about operating system development lately, and I have run into some strange issues regarding floating point division in C. Even something as simple as 4.0f / 2.0f gives me a NaN result. I suspect this may have something to do with the compiler, however I don't know how to verify that, I would very much appreciate help in fixing this, as I've been at this for a few hours and have made little to no progress with google searches.
Github for the project, if you'd like to build it: https://github.com/AsherBearce/ToyOperatingSystem
The relevant parts of my project are as follows:
kernel/kernelmain.c:
#include "screen.h"
void main(){
enableCursor(1, 14);
clearScreen();
double a = 4.0f;
double b = 2.0f;
double c = a / b;
double ans = 2.0f;
//Division is the ONLY operation that isn't yielding the correct results, in fact c turns out to be NaN!
if (c == 2.0f){
char string[] = "Hardcoded values were correct\n\0";
print(string);
}
char out[] = "End output\0";
print(out);
while (1){
}
}
boot/bootsector.asm
org 0x7c00
bits 16
mov ax, HELLO_MSG ;Print a simple hello message :D
call _printString
xor ax, ax
;Here, we'll load the kernel into RAM
call LoadKernel
;Enter protected mode
call EnterProtMode
EnterProtMode:
cli ;Disable interrupts
lgdt [gdt_pointer] ;Load the GDT register with the start address of the GDT
mov eax, cr0
or al, 1 ;Set PE (protection enable) bit in CR0
mov cr0, eax
jmp 08h:Stage2 ;Jump to stage 2
LoadKernel:
mov bx, KERNEL_OFFSET ;Load the kernel offset into bx
mov dh, 16 ;Load 16 sectors
mov dl, [BOOT_DRIVE] ;The disk to read from
call diskload ;Load the kernel
ret
bits 32
KERNEL_OFFSET equ 0x1000
BOOT_DRIVE: db 0
Stage2:
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov ebp, 0x90000
mov esp, ebp
;Kernel entry here
jmp KERNEL_OFFSET ;Call the kernel finally
%include 'boot/printUtils.asm'
%include 'boot/gdt.asm'
%include 'boot/diskload.asm'
HELLO_MSG: db "Booted successfully, loading kernel.", 0
times 510 - ($ - $$) db 0
dw 0xaa55
Makefile
BOOTOUTPUT = boot.bin
OSOUTPUT = os.bin
SRCS = $(shell find . -name '*.c')
CINC = $(shell find . -name '*.h')
COBJS = $(patsubst %.c, %.o, $(SRCS))
OBJDIR = build
#Final step in the build process
$(OSOUTPUT): kernel.bin $(BOOTOUTPUT)
cat $(BOOTOUTPUT) kernel.bin > $(OSOUTPUT)
#Assemble the boot sector code
$(BOOTOUTPUT): boot/bootsector.asm
nasm -f bin boot/bootsector.asm -o $(BOOTOUTPUT)
#Compile all the kernel C files
%.o:%.c $(CINC)
gcc -m32 -ffreestanding -fno-pie -fno-stack-protector -nostdlib -c $< -o $#
#Assemble the IRQ code
irq.o: kernel/irq.asm
nasm kernel/irq.asm -f elf32 -o irq.o
#Assemble the kernel entry code
kernelEntry.o: boot/kernelEntry.asm
nasm boot/kernelEntry.asm -f elf32 -o kernelEntry.o
#Link all the .o files with the kernel entry
kernel.bin: kernelEntry.o irq.o $(COBJS)
ld -melf_i386 -o kernel.bin -Ttext 0x1000 $^ --oformat binary
run:
qemu-system-x86_64 -fda $(OSOUTPUT)
clean:
rm -f *.bin *.o $(COBJS)
Edit: I've decided to include the disassembly for kernelmain.c
kernelmain.o: file format elf32-i386
Disassembly of section .text:
00000000 <main>:
0: f3 0f 1e fb endbr32
4: 8d 4c 24 04 lea 0x4(%esp),%ecx
8: 83 e4 f0 and $0xfffffff0,%esp
b: ff 71 fc pushl -0x4(%ecx)
e: 55 push %ebp
f: 89 e5 mov %esp,%ebp
11: 51 push %ecx
12: 83 ec 54 sub $0x54,%esp
15: e8 fc ff ff ff call 16 <main+0x16>
1a: 83 ec 08 sub $0x8,%esp
1d: 6a 0e push $0xe
1f: 6a 01 push $0x1
21: e8 fc ff ff ff call 22 <main+0x22>
26: 83 c4 10 add $0x10,%esp
29: e8 fc ff ff ff call 2a <main+0x2a>
2e: e8 fc ff ff ff call 2f <main+0x2f>
33: dd 05 00 00 00 00 fldl 0x0
39: dd 5d f0 fstpl -0x10(%ebp)
3c: dd 05 08 00 00 00 fldl 0x8
42: dd 5d e8 fstpl -0x18(%ebp)
45: dd 45 f0 fldl -0x10(%ebp)
48: dc 75 e8 fdivl -0x18(%ebp)
4b: dd 5d e0 fstpl -0x20(%ebp)
4e: dd 05 08 00 00 00 fldl 0x8
54: dd 5d d8 fstpl -0x28(%ebp)
57: dd 45 e0 fldl -0x20(%ebp)
5a: dd 05 08 00 00 00 fldl 0x8
60: df e9 fucomip %st(1),%st
62: dd d8 fstp %st(0)
64: 7a 56 jp bc <main+0xbc>
66: dd 45 e0 fldl -0x20(%ebp)
69: dd 05 08 00 00 00 fldl 0x8
6f: df e9 fucomip %st(1),%st
71: dd d8 fstp %st(0)
73: 75 47 jne bc <main+0xbc>
75: c7 45 ac 48 61 72 64 movl $0x64726148,-0x54(%ebp)
7c: c7 45 b0 63 6f 64 65 movl $0x65646f63,-0x50(%ebp)
83: c7 45 b4 64 20 76 61 movl $0x61762064,-0x4c(%ebp)
8a: c7 45 b8 6c 75 65 73 movl $0x7365756c,-0x48(%ebp)
91: c7 45 bc 20 77 65 72 movl $0x72657720,-0x44(%ebp)
98: c7 45 c0 65 20 63 6f movl $0x6f632065,-0x40(%ebp)
9f: c7 45 c4 72 72 65 63 movl $0x63657272,-0x3c(%ebp)
a6: c7 45 c8 74 0a 00 00 movl $0xa74,-0x38(%ebp)
ad: 83 ec 0c sub $0xc,%esp
b0: 8d 45 ac lea -0x54(%ebp),%eax
b3: 50 push %eax
b4: e8 fc ff ff ff call b5 <main+0xb5>
b9: 83 c4 10 add $0x10,%esp
bc: c7 45 cc 45 6e 64 20 movl $0x20646e45,-0x34(%ebp)
c3: c7 45 d0 6f 75 74 70 movl $0x7074756f,-0x30(%ebp)
ca: c7 45 d4 75 74 00 00 movl $0x7475,-0x2c(%ebp)
d1: 83 ec 0c sub $0xc,%esp
d4: 8d 45 cc lea -0x34(%ebp),%eax
d7: 50 push %eax
d8: e8 fc ff ff ff call d9 <main+0xd9>
dd: 83 c4 10 add $0x10,%esp
e0: eb fe jmp e0 <main+0xe0>
After looking around at various resources, I found this forum page on OSdev here:
forum.osdev.org/viewtopic.php?f=1&t=21813 that described the process for first checking for an FPU, and then initializing it. Turns out that for whatever reason, my target platform does not have an FPU, which I'm guessing is the reason for the undefined behavior.
I use ghidra armv7 reverse firmware.
Analyzing to address 0x0002843a looks like r0 loads the data of address 0x0002881c but address 0x0002881c addr looks like an instruction.
I read the ARM®v7-M ArchitectureReference Manual and do not see the addr instruction.
I don’t understand what addr means, please help me.
**************************************************************
* FUNCTION *
**************************************************************
undefined FUN_0002842e()
assume LRset = 0x0
assume TMode = 0x1
undefined r0:1 <RETURN>
FUN_0002842e XREF[1]: FUN_0002706c:00027168(c)
0002842e 10 b5 push { r4, lr }
00028430 04 46 mov r4,r0
00028432 20 46 mov r0,r4
00028434 ff f7 52 fe bl FUN_000280dc undefined FUN_000280dc()
00028438 04 46 mov r4,r0
0002843a f8 48 ldr r0,[PTR_PTR_FUN_00028488+1_0002881c] = 0066a66c**
0002843c 20 60 str r0=>PTR_FUN_00028488+1_0066a66c,[r4,#0x0] = 00028489
0002843e 00 20 mov r0,#0x0
00028440 60 60 str r0,[r4,#0x4]
00028442 a0 60 str r0,[r4,#0x8]
00028444 20 61 str r0,[r4,#0x10]
00028446 e0 60 str r0,[r4,#0xc]
00028448 60 61 str r0,[r4,#0x14]
0002844a 00 21 mov r1,#0x0
0002844c 5c 20 mov r0,#0x5c
0002844e 01 55 strb r1,[r0,r4]
00028450 5d 20 mov r0,#0x5d
00028452 01 55 strb r1,[r0,r4]
00028454 5e 20 mov r0,#0x5e
00028456 01 55 strb r1,[r0,r4]
00028458 00 20 mov r0,#0x0
0002845a a0 63 str r0,[r4,#0x38]
0002845c e1 63 str r1,[r4,#0x3c]
0002845e a0 64 str r0,[r4,#0x48]
00028460 02 21 mov r1,#0x2
00028462 e1 64 str r1,[r4,#0x4c]
00028464 ee 48 ldr r0,[DAT_00028820] = 188DA314h
00028466 00 6c ldr r0,[r0,#0x40]=>DAT_188da354
00028468 00 28 cmp r0,#0x0
0002846a 03 d1 bne LAB_00028474
0002846c ec 48 ldr r0,[DAT_00028820] = 188DA314h
0002846e 44 30 add r0,#0x44
00028470 eb 49 ldr r1,[DAT_00028820] = 188DA314h
00028472 08 64 str r0,[r1,#0x40]=>DAT_188da354
LAB_00028474 XREF[1]: 0002846a(j)
00028474 eb 48 ldr r0,[DAT_00028824] = 188DA494h
00028476 80 6b ldr r0,[r0,#0x38]=>DAT_188da4cc
00028478 00 28 cmp r0,#0x0
0002847a 03 d1 bne LAB_00028484
0002847c e9 49 ldr r1,[DAT_00028824] = 188DA494h
0002847e 3c 31 add r1,#0x3c
00028480 e8 48 ldr r0,[DAT_00028824] = 188DA494h
00028482 81 63 str r1,[r0,#0x38]=>DAT_188da4cc
LAB_00028484 XREF[1]: 0002847a(j)
00028484 20 46 mov r0,r4
00028486 10 bd pop { r4, pc }
PTR_PTR_FUN_00028488+1_0002881c XREF[1]: FUN_0002842e:0002843a(R)
0002881c 6c a6 66 00 addr PTR_FUN_00028488+1_0066a66c = 00028489
PTR_FUN_00028488+1_0066a66c XREF[2]: FUN_0002842e:0002843c(*),
0002881c(*)
0066a66c 89 84 02 00 addr FUN_00028488+1
0066a670 99 84 02 00 addr FUN_00028498+1
0066a674 d5 90 02 00 addr FUN_000290d4+1
0066a678 45 d8 02 00 addr FUN_0002d844+1
0066a67c 73 da 02 00 addr LAB_0002da72+1
0066a680 75 da 02 00 addr FUN_0002da74+1
0066a684 c7 d9 02 00 addr DAT_0002d9c7 = B5h
0066a688 fb 80 02 00 addr LAB_000280fa+1
addr is an assembler directive: it initialises the next four bytes (or eight bytes in 64-bit mode) to the address of its argument. (The +1 after all your function addresses means that you are in Thumb mode, which is indicated by bit 0 of the PC being set to 1. I confess I have never seen the strange PTR_FUN_00028488+1_0066a66c syntax. Perhaps others can explain it.)
These addresses are never reached at execution time, because of the pop instruction.
I'm currently studying C and I have a question in which I have to guess what values are in the memory.
When I say, for example long var1[1243] = {10, 1, 0, -1, -10} and define this vector, the first 5 elements of it are already defined, but the allocated bytes that represent the remaining 1238 elements, what are they set as in memory? More specifically, are they 0? Would saying, in assembly, after defining them, .zero <number of remaining bytes in vector> correct?
By having at least some elements initialized {10} C will initialize all the remaining elements in the array the same as a global variable. Either numeric zero or null pointer depending on type, and in the case of arrays of structs, all members of the struct, recursively.
In C++ an empty initializer also works long var1[1243] = {}, but that is not allowed in C.
Why not just try it?
long var1[1243] = {10, 1, 0, -1, -10};
long so ( unsigned int x )
{
long var2[1243] = {10, 1, 0, -1, -10};
return(var2[x]);
}
Compile and disassemble
Disassembly of section .text:
00000000 <so>:
0: e92d4010 push {r4, lr}
4: e24ddd4d sub sp, sp, #4928 ; 0x1340
8: e24dd030 sub sp, sp, #48 ; 0x30
c: e1a04000 mov r4, r0
10: e3a01000 mov r1, #0
14: e59f203c ldr r2, [pc, #60] ; 58 <so+0x58>
18: e28d0004 add r0, sp, #4
1c: ebfffffe bl 0 <memset>
20: e3a0000a mov r0, #10
24: e3a01001 mov r1, #1
28: e3e02000 mvn r2, #0
2c: e3e03009 mvn r3, #9
30: e98d0003 stmib sp, {r0, r1}
34: e58d3014 str r3, [sp, #20]
38: e58d2010 str r2, [sp, #16]
3c: e28d3e37 add r3, sp, #880 ; 0x370
40: e0830104 add r0, r3, r4, lsl #2
44: e510036c ldr r0, [r0, #-876] ; 0xfffffc94
48: e28ddd4d add sp, sp, #4928 ; 0x1340
4c: e28dd030 add sp, sp, #48 ; 0x30
50: e8bd4010 pop {r4, lr}
54: e12fff1e bx lr
58: 0000136c andeq r1, r0, r12, ror #6
Disassembly of section .data:
00000000 <var1>:
0: 0000000a andeq r0, r0, r10
4: 00000001 andeq r0, r0, r1
8: 00000000 andeq r0, r0, r0
c: ffffffff ; <UNDEFINED> instruction: 0xffffffff
10: fffffff6 ; <UNDEFINED> instruction: 0xfffffff6
...
To confirm the ... if I link it then I see zeros in .data:
00000000 10 40 2d e9 4d dd 4d e2 30 d0 4d e2 00 40 a0 e1 |.#-.M.M.0.M..#..|
00000010 00 10 a0 e3 3c 20 9f e5 04 00 8d e2 0e 00 00 eb |....< ..........|
00000020 0a 00 a0 e3 01 10 a0 e3 00 20 e0 e3 09 30 e0 e3 |......... ...0..|
00000030 03 00 8d e9 14 30 8d e5 10 20 8d e5 37 3e 8d e2 |.....0... ..7>..|
00000040 04 01 83 e0 6c 03 10 e5 4d dd 8d e2 30 d0 8d e2 |....l...M...0...|
00000050 10 40 bd e8 1e ff 2f e1 6c 13 00 00 1e ff 2f e1 |.#..../.l...../.|
00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00001000 0a 00 00 00 01 00 00 00 00 00 00 00 ff ff ff ff |................|
00001010 f6 ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00001020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
0000236c
So for both the local and global versions gcc is at least is zero padding the rest. But as pointed out in a comment you should see the spec, just because one compiler doesn't, it doesn't mean that is how it is supposed to work or always works.