Issues with ARMv7-A bare metal call stack [duplicate] - c

This question already has an answer here:
Rustc/LLVM generates faulty code for aarch64 with opt-level=0
(1 answer)
Closed 7 years ago.
I'm trying to get a small ARM kernel up and running on QEMU (Versatile Express for Cortex-A15). Currently it simply sets sp to the top of a small stack and sends a single character to UART0.
_start.arm:
.set stack_size, 0x10000
.comm stack, stack_size
.global _start
_start:
ldr sp, =stack+stack_size
bl start
1:
b 1b
.size _start, . - _start
start.c:
/* UART_0 is a struct overlaid on 0x1c090000 */
void printChar(char c)
{
while (UART_0->flags & TRANSMIT_FULL);
UART_0->data = c;
}
void start()
{
while (UART_0->flags & TRANSMIT_FULL);
UART_0->data = 'A';
printChar('a');
}
From GDB, I know that execution progresses through _start into start and successfully sends 'A' to UART_0. printChar gets called and completes, but doesn't seem to print anything to the serial port . When running without GDB, the kernel repeatedly prints 'A', though I'm not sure if this is the processor resetting or jumping incorrectly.
From objdump:
Disassembly of section .stub:
00010000 <_start>:
10000: e59fd004 ldr sp, [pc, #4] ; 1000c <__STACK_SIZE+0xc>
10004: eb000016 bl 10064 <start>
10008: eafffffe b 10008 <_start+0x8>
1000c: 000200d0 .word 0x000200d0
Disassembly of section .text:
00010010 <printChar>:
10010: e52db004 push {fp} ; (str fp, [sp, #-4]!)
10014: e28db000 add fp, sp, #0
10018: e24dd00c sub sp, sp, #12
1001c: e1a03000 mov r3, r0
10020: e54b3005 strb r3, [fp, #-5]
10024: e1a00000 nop ; (mov r0, r0)
10028: e3a03000 mov r3, #0
1002c: e3413c09 movt r3, #7177 ; 0x1c09
10030: e1d331ba ldrh r3, [r3, #26]
10034: e6ff3073 uxth r3, r3
10038: e2033020 and r3, r3, #32
1003c: e3530000 cmp r3, #0
10040: 1afffff8 bne 10028 <printChar+0x18>
10044: e3a03000 mov r3, #0
10048: e3413c09 movt r3, #7177 ; 0x1c09
1004c: e55b2005 ldrb r2, [fp, #-5]
10050: e6ff2072 uxth r2, r2
10054: e1c320b2 strh r2, [r3, #2]
10058: e24bd000 sub sp, fp, #0
1005c: e49db004 pop {fp} ; (ldr fp, [sp], #4)
10060: e12fff1e bx lr
00010064 <start>:
10064: e52db008 str fp, [sp, #-8]!
10068: e58de004 str lr, [sp, #4]
1006c: e28db004 add fp, sp, #4
10070: e1a00000 nop ; (mov r0, r0)
10074: e3a03000 mov r3, #0
10078: e3413c09 movt r3, #7177 ; 0x1c09
1007c: e1d331ba ldrh r3, [r3, #26]
10080: e6ff3073 uxth r3, r3
10084: e2033020 and r3, r3, #32
10088: e3530000 cmp r3, #0
1008c: 1afffff8 bne 10074 <start+0x10>
10090: e3a03000 mov r3, #0
10094: e3413c09 movt r3, #7177 ; 0x1c09
10098: e5d32002 ldrb r2, [r3, #2]
1009c: e3a02000 mov r2, #0
100a0: e3822041 orr r2, r2, #65 ; 0x41
100a4: e5c32002 strb r2, [r3, #2]
100a8: e5d32003 ldrb r2, [r3, #3]
100ac: e3a02000 mov r2, #0
100b0: e5c32003 strb r2, [r3, #3]
100b4: e3a00061 mov r0, #97 ; 0x61
100b8: ebffffd4 bl 10010 <printChar>
100bc: e24bd004 sub sp, fp, #4
100c0: e59db000 ldr fp, [sp]
100c4: e28dd004 add sp, sp, #4
100c8: e49df004 pop {pc} ; (ldr pc, [sp], #4)
000100cc <UART_0>:
100cc: 1c090000 ....

I may have missed something, but I am not seeing where you have enabled interrupts, or poll to see if you can send the next character. If you have enabled the interrupts and set up the UART hardware correctly, your driver my have a bug. If you have not setup the UART hardware correctly, it may not be generating interrupts, or it may not be doing the FIFO correctly, or any number of other problems.

Related

Timer interrupts in ARM processor QEMU not occurring

I am trying to get interrupts to work on an ARM processor using QEMU. I have tried Google and various attempts to solve it, but I cannot get my IRQ handler to be called.
I also tried keyboard interrupts, which did not work either. I think the book I have may have a few mistakes, as the UART driver ended up being slightly different than described.
My assembly code:
.code 32
.global start, vectors_start, vectors_end, lock, unlock
start:
LDR sp, =stack_top
BL copy_vector
MSR cpsr, #0x92
LDR sp, =irq_stack_top
MSR cpsr, #0x13
bl unlock
BL main
B .
irq_handler:
sub lr, lr, #4
stmfd sp!, {r0-r12, lr}
bl IRQ_handler
ldmfd sp!, {r0-r12, pc}^
vectors_start:
LDR PC, reset_handler_addr
LDR PC, undef_handler_addr
LDR PC, swi_handler_addr
LDR PC, prefetch_abort_handler_addr
LDR PC, data_abort_handler_addr
B .
LDR PC, irq_handler_addr
LDR PC, fiq_handler_addr
reset_handler_addr: .word start
undef_handler_addr: .word undef_handler
swi_handler_addr: .word swi_handler
prefetch_abort_handler_addr: .word prefetch_abort_handler
data_abort_handler_addr: .word data_abort_handler
irq_handler_addr: .word irq_handler
fiq_handler_addr: .word fiq_handler
vectors_end:
lock:
MRS r0, CPSR
ORR r0,r0,#0x80
MSR CPSR, r0
mov PC, lr
unlock:
MRS r0,CPSR
BIC r0,r0,#0x80
MSR CPSR, r0
mov PC, lr
Relevant C functions:
void copy_vector(void){
extern u32 vectors_start, vectors_end;
u32 *vectors_src = &vectors_start;
u32 *vectors_dst = (u32 *) 0;
while (vectors_src<&vectors_end){
*vectors_dst++ = *vectors_src++;
}
}
// this function has been modified somewhat because the book was incomplete
// the print statement never prints
void IRQ_handler(void){
int vicstatus = 0;
uprints(uarts,"in interupt");
// int vicstatus = 0;
if(1){
if(*(tp[0]->base+TVALUE)==0){
timer_handler(0);
}
if(*(tp[1]->base+TVALUE)==0){
timer_handler(1);
}
}
if( 1){
if(*(tp[2]->base+TVALUE)==0){
timer_handler(2);
}
if(*(tp[3]->base+TVALUE)==0){
timer_handler(3);
}
}
}
void timer_init()
{
// timers[0].base = (u32*) 0x101E2000;
// timers[1].base = (u32*) 0x101E2020;
// timers[2].base = (u32*) 0x101E3000;
// timers[3].base = (u32*) 0x101E3020;
int i; TIMER * tp;
for (i = 0; i<4; ++i){
tp = &timers[i];
if(i==0) tp->base = (u32*) 0x101E2000;
if(i==1) tp->base = (u32*) 0x101E2020;
if (i == 2) tp->base = (u32*) 0x101E3000;
if (i == 3) tp->base = (u32*) 0x101E3020;
*(tp->base+TLOAD) = 0x0;
*(tp->base+TVALUE) = 0xFFFFFFFF;
*(tp->base+TRIS) = 0x0;
*(tp->base+TMIS) = 0x0;
*(tp->base+TLOAD) = 0x100;
*(tp->base+TCNTL) = 0x66;
*(tp->base+TBGLOAD) = 0x1C00;
*(tp->base ) |= (unsigned int)(1<<6);
tp->tick = 0;
///uprints(uarts,"timer init");
}
}
When I reset the machine in QEMU I get the message Timer with delta zero disabling.
I can get the message to disappear by changing: *(tp->base+TLOAD) = 0x0;
to *(tp->base+TLOAD) = 0x1; but the timer still doesn't work.
Lastly, my build script is:
arm-none-eabi-as -o start3.o start3.s
arm-none-eabi-gcc -c main3.c
arm-none-eabi-ld -T t.ld -o start3.elf start3.o main3.o
arm-none-eabi-nm start3.elf
arm-none-eabi-objcopy -O binary start3.elf start3.bin
qemu-system-arm -M versatilepb -m 128M -kernel start3.bin
edit: in addition here is the disassembled code from my main.c file (which includes a few other c files for the drivers)
the board is the versatilepb which according to the docs emulates the following:
ARM926E, ARM1136 or Cortex-A8 CPU
00000000 <uart_init>:
0: e52db004 push {fp} ; (str fp, [sp, #-4]!)
4: e28db000 add fp, sp, #0
8: e24dd00c sub sp, sp, #12
c: e3a03000 mov r3, #0
10: e50b3008 str r3, [fp, #-8]
14: ea000011 b 60 <uart_init+0x60>
18: e51b3008 ldr r3, [fp, #-8]
1c: e1a03183 lsl r3, r3, #3
20: e59f2064 ldr r2, [pc, #100] ; 8c <uart_init+0x8c>
24: e0833002 add r3, r3, r2
28: e50b300c str r3, [fp, #-12]
2c: e51b2008 ldr r2, [fp, #-8]
30: e59f3058 ldr r3, [pc, #88] ; 90 <uart_init+0x90>
34: e0823003 add r3, r2, r3
38: e1a03603 lsl r3, r3, #12
3c: e1a02003 mov r2, r3
40: e51b300c ldr r3, [fp, #-12]
44: e5832000 str r2, [r3]
48: e51b300c ldr r3, [fp, #-12]
4c: e51b2008 ldr r2, [fp, #-8]
50: e5832004 str r2, [r3, #4]
54: e51b3008 ldr r3, [fp, #-8]
58: e2833001 add r3, r3, #1
5c: e50b3008 str r3, [fp, #-8]
60: e51b3008 ldr r3, [fp, #-8]
64: e3530003 cmp r3, #3
68: daffffea ble 18 <uart_init+0x18>
6c: e59f3018 ldr r3, [pc, #24] ; 8c <uart_init+0x8c>
70: e59f201c ldr r2, [pc, #28] ; 94 <uart_init+0x94>
74: e5832018 str r2, [r3, #24]
78: e1a00000 nop ; (mov r0, r0)
7c: e1a00003 mov r0, r3
80: e28bd000 add sp, fp, #0
84: e49db004 pop {fp} ; (ldr fp, [sp], #4)
88: e12fff1e bx lr
8c: 00000000 .word 0x00000000
90: 000101f1 .word 0x000101f1
94: 10009000 .word 0x10009000
00000098 <ugetc>:
98: e52db004 push {fp} ; (str fp, [sp, #-4]!)
9c: e28db000 add fp, sp, #0
a0: e24dd00c sub sp, sp, #12
a4: e50b0008 str r0, [fp, #-8]
a8: e1a00000 nop ; (mov r0, r0)
ac: e51b3008 ldr r3, [fp, #-8]
b0: e5933000 ldr r3, [r3]
b4: e2833018 add r3, r3, #24
b8: e5d33000 ldrb r3, [r3]
bc: e2033010 and r3, r3, #16
c0: e3530000 cmp r3, #0
c4: 1afffff8 bne ac <ugetc+0x14>
c8: e51b3008 ldr r3, [fp, #-8]
cc: e5933000 ldr r3, [r3]
d0: e5d33000 ldrb r3, [r3]
d4: e1a00003 mov r0, r3
d8: e28bd000 add sp, fp, #0
dc: e49db004 pop {fp} ; (ldr fp, [sp], #4)
e0: e12fff1e bx lr
000000e4 <uputc>:
e4: e52db004 push {fp} ; (str fp, [sp, #-4]!)
e8: e28db000 add fp, sp, #0
ec: e24dd00c sub sp, sp, #12
f0: e50b0008 str r0, [fp, #-8]
f4: e1a03001 mov r3, r1
f8: e54b3009 strb r3, [fp, #-9]
fc: e1a00000 nop ; (mov r0, r0)
100: e51b3008 ldr r3, [fp, #-8]
104: e5933000 ldr r3, [r3]
108: e2833018 add r3, r3, #24
10c: e5d33000 ldrb r3, [r3]
110: e2033020 and r3, r3, #32
114: e3530000 cmp r3, #0
118: 1afffff8 bne 100 <uputc+0x1c>
11c: e51b3008 ldr r3, [fp, #-8]
120: e5933000 ldr r3, [r3]
124: e55b2009 ldrb r2, [fp, #-9]
128: e5c32000 strb r2, [r3]
12c: e1a00000 nop ; (mov r0, r0)
130: e1a00003 mov r0, r3
134: e28bd000 add sp, fp, #0
138: e49db004 pop {fp} ; (ldr fp, [sp], #4)
13c: e12fff1e bx lr
00000140 <ugets>:
140: e92d4800 push {fp, lr}
144: e28db004 add fp, sp, #4
148: e24dd008 sub sp, sp, #8
14c: e50b0008 str r0, [fp, #-8]
150: e50b100c str r1, [fp, #-12]
154: ea000007 b 178 <ugets+0x38>
158: e51b300c ldr r3, [fp, #-12]
15c: e5d33000 ldrb r3, [r3]
160: e1a01003 mov r1, r3
164: e51b0008 ldr r0, [fp, #-8]
168: ebfffffe bl e4 <uputc>
16c: e51b300c ldr r3, [fp, #-12]
170: e2833001 add r3, r3, #1
174: e50b300c str r3, [fp, #-12]
178: e51b0008 ldr r0, [fp, #-8]
17c: ebfffffe bl 98 <ugetc>
180: e1a03000 mov r3, r0
184: e20320ff and r2, r3, #255 ; 0xff
188: e51b300c ldr r3, [fp, #-12]
18c: e5c32000 strb r2, [r3]
190: e51b300c ldr r3, [fp, #-12]
194: e5d33000 ldrb r3, [r3]
198: e353000d cmp r3, #13
19c: 1affffed bne 158 <ugets+0x18>
1a0: e51b300c ldr r3, [fp, #-12]
1a4: e3a02000 mov r2, #0
1a8: e5c32000 strb r2, [r3]
1ac: e1a00000 nop ; (mov r0, r0)
1b0: e1a00003 mov r0, r3
1b4: e24bd004 sub sp, fp, #4
1b8: e8bd4800 pop {fp, lr}
1bc: e12fff1e bx lr
000001c0 <uprints>:
1c0: e92d4800 push {fp, lr}
1c4: e28db004 add fp, sp, #4
1c8: e24dd008 sub sp, sp, #8
1cc: e50b0008 str r0, [fp, #-8]
1d0: e50b100c str r1, [fp, #-12]
1d4: ea000006 b 1f4 <uprints+0x34>
1d8: e51b300c ldr r3, [fp, #-12]
1dc: e2832001 add r2, r3, #1
1e0: e50b200c str r2, [fp, #-12]
1e4: e5d33000 ldrb r3, [r3]
1e8: e1a01003 mov r1, r3
1ec: e51b0008 ldr r0, [fp, #-8]
1f0: ebfffffe bl e4 <uputc>
1f4: e51b300c ldr r3, [fp, #-12]
1f8: e5d33000 ldrb r3, [r3]
1fc: e3530000 cmp r3, #0
200: 1afffff4 bne 1d8 <uprints+0x18>
204: e1a00000 nop ; (mov r0, r0)
208: e1a00003 mov r0, r3
20c: e24bd004 sub sp, fp, #4
210: e8bd4800 pop {fp, lr}
214: e12fff1e bx lr
00000218 <fbuf_init>:
218: e52db004 push {fp} ; (str fp, [sp, #-4]!)
21c: e28db000 add fp, sp, #0
220: e59f3060 ldr r3, [pc, #96] ; 288 <fbuf_init+0x70>
224: e3a02602 mov r2, #2097152 ; 0x200000
228: e5832000 str r2, [r3]
22c: e59f3058 ldr r3, [pc, #88] ; 28c <fbuf_init+0x74>
230: e59f2058 ldr r2, [pc, #88] ; 290 <fbuf_init+0x78>
234: e5832000 str r2, [r3]
238: e59f3054 ldr r3, [pc, #84] ; 294 <fbuf_init+0x7c>
23c: e59f2054 ldr r2, [pc, #84] ; 298 <fbuf_init+0x80>
240: e5832000 str r2, [r3]
244: e59f3050 ldr r3, [pc, #80] ; 29c <fbuf_init+0x84>
248: e59f2050 ldr r2, [pc, #80] ; 2a0 <fbuf_init+0x88>
24c: e5832000 str r2, [r3]
250: e59f304c ldr r3, [pc, #76] ; 2a4 <fbuf_init+0x8c>
254: e59f204c ldr r2, [pc, #76] ; 2a8 <fbuf_init+0x90>
258: e5832000 str r2, [r3]
25c: e59f3048 ldr r3, [pc, #72] ; 2ac <fbuf_init+0x94>
260: e3a02602 mov r2, #2097152 ; 0x200000
264: e5832000 str r2, [r3]
268: e59f3040 ldr r3, [pc, #64] ; 2b0 <fbuf_init+0x98>
26c: e59f2040 ldr r2, [pc, #64] ; 2b4 <fbuf_init+0x9c>
270: e5832000 str r2, [r3]
274: e1a00000 nop ; (mov r0, r0)
278: e1a00003 mov r0, r3
27c: e28bd000 add sp, fp, #0
280: e49db004 pop {fp} ; (ldr fp, [sp], #4)
284: e12fff1e bx lr
288: 00000000 .word 0x00000000
28c: 1000001c .word 0x1000001c
290: 00002c77 .word 0x00002c77
294: 10120000 .word 0x10120000
298: 3f1f3f9c .word 0x3f1f3f9c
29c: 10120004 .word 0x10120004
2a0: 090b61df .word 0x090b61df
2a4: 10120008 .word 0x10120008
2a8: 071f1800 .word 0x071f1800
2ac: 10120010 .word 0x10120010
2b0: 10120018 .word 0x10120018
2b4: 0000082b .word 0x0000082b
000002b8 <draw_box>:
2b8: e52db004 push {fp} ; (str fp, [sp, #-4]!)
2bc: e28db000 add fp, sp, #0
2c0: e24dd01c sub sp, sp, #28
2c4: e50b0010 str r0, [fp, #-16]
2c8: e50b1014 str r1, [fp, #-20] ; 0xffffffec
2cc: e50b2018 str r2, [fp, #-24] ; 0xffffffe8
2d0: e50b301c str r3, [fp, #-28] ; 0xffffffe4
2d4: e3a03000 mov r3, #0
2d8: e50b3008 str r3, [fp, #-8]
2dc: ea00001c b 354 <draw_box+0x9c>
2e0: e3a03000 mov r3, #0
2e4: e50b300c str r3, [fp, #-12]
2e8: ea000012 b 338 <draw_box+0x80>
2ec: e59f3084 ldr r3, [pc, #132] ; 378 <draw_box+0xc0>
2f0: e5932000 ldr r2, [r3]
2f4: e51b100c ldr r1, [fp, #-12]
2f8: e51b3014 ldr r3, [fp, #-20] ; 0xffffffec
2fc: e0813003 add r3, r1, r3
300: e59f1074 ldr r1, [pc, #116] ; 37c <draw_box+0xc4>
304: e5911000 ldr r1, [r1]
308: e0010193 mul r1, r3, r1
30c: e51b3008 ldr r3, [fp, #-8]
310: e0811003 add r1, r1, r3
314: e51b3010 ldr r3, [fp, #-16]
318: e0813003 add r3, r1, r3
31c: e1a03103 lsl r3, r3, #2
320: e0823003 add r3, r2, r3
324: e51b201c ldr r2, [fp, #-28] ; 0xffffffe4
328: e5832000 str r2, [r3]
32c: e51b300c ldr r3, [fp, #-12]
330: e2833001 add r3, r3, #1
334: e50b300c str r3, [fp, #-12]
338: e51b200c ldr r2, [fp, #-12]
33c: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
340: e1520003 cmp r2, r3
344: baffffe8 blt 2ec <draw_box+0x34>
348: e51b3008 ldr r3, [fp, #-8]
34c: e2833001 add r3, r3, #1
350: e50b3008 str r3, [fp, #-8]
354: e51b2008 ldr r2, [fp, #-8]
358: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
35c: e1520003 cmp r2, r3
360: baffffde blt 2e0 <draw_box+0x28>
364: e1a00000 nop ; (mov r0, r0)
368: e1a00000 nop ; (mov r0, r0)
36c: e28bd000 add sp, fp, #0
370: e49db004 pop {fp} ; (ldr fp, [sp], #4)
374: e12fff1e bx lr
...
00000380 <timer_init>:
380: e52db004 push {fp} ; (str fp, [sp, #-4]!)
384: e28db000 add fp, sp, #0
388: e24dd00c sub sp, sp, #12
38c: e3a03000 mov r3, #0
390: e50b3008 str r3, [fp, #-8]
394: ea000048 b 4bc <timer_init+0x13c>
398: e51b3008 ldr r3, [fp, #-8]
39c: e1a03183 lsl r3, r3, #3
3a0: e59f2134 ldr r2, [pc, #308] ; 4dc <timer_init+0x15c>
3a4: e0833002 add r3, r3, r2
3a8: e50b300c str r3, [fp, #-12]
3ac: e51b3008 ldr r3, [fp, #-8]
3b0: e3530000 cmp r3, #0
3b4: 1a000002 bne 3c4 <timer_init+0x44>
3b8: e51b300c ldr r3, [fp, #-12]
3bc: e59f211c ldr r2, [pc, #284] ; 4e0 <timer_init+0x160>
3c0: e5832000 str r2, [r3]
3c4: e51b3008 ldr r3, [fp, #-8]
3c8: e3530001 cmp r3, #1
3cc: 1a000002 bne 3dc <timer_init+0x5c>
3d0: e51b300c ldr r3, [fp, #-12]
3d4: e59f2108 ldr r2, [pc, #264] ; 4e4 <timer_init+0x164>
3d8: e5832000 str r2, [r3]
3dc: e51b3008 ldr r3, [fp, #-8]
3e0: e3530002 cmp r3, #2
3e4: 1a000002 bne 3f4 <timer_init+0x74>
3e8: e51b300c ldr r3, [fp, #-12]
3ec: e59f20f4 ldr r2, [pc, #244] ; 4e8 <timer_init+0x168>
3f0: e5832000 str r2, [r3]
3f4: e51b3008 ldr r3, [fp, #-8]
3f8: e3530003 cmp r3, #3
3fc: 1a000002 bne 40c <timer_init+0x8c>
400: e51b300c ldr r3, [fp, #-12]
404: e59f20e0 ldr r2, [pc, #224] ; 4ec <timer_init+0x16c>
408: e5832000 str r2, [r3]
40c: e51b300c ldr r3, [fp, #-12]
410: e5933000 ldr r3, [r3]
414: e3a02000 mov r2, #0
418: e5832000 str r2, [r3]
41c: e51b300c ldr r3, [fp, #-12]
420: e5933000 ldr r3, [r3]
424: e2833004 add r3, r3, #4
428: e3e02000 mvn r2, #0
42c: e5832000 str r2, [r3]
430: e51b300c ldr r3, [fp, #-12]
434: e5933000 ldr r3, [r3]
438: e2833010 add r3, r3, #16
43c: e3a02000 mov r2, #0
440: e5832000 str r2, [r3]
444: e51b300c ldr r3, [fp, #-12]
448: e5933000 ldr r3, [r3]
44c: e2833014 add r3, r3, #20
450: e3a02000 mov r2, #0
454: e5832000 str r2, [r3]
458: e51b300c ldr r3, [fp, #-12]
45c: e5933000 ldr r3, [r3]
460: e3a02c01 mov r2, #256 ; 0x100
464: e5832000 str r2, [r3]
468: e51b300c ldr r3, [fp, #-12]
46c: e5933000 ldr r3, [r3]
470: e2833008 add r3, r3, #8
474: e3a02066 mov r2, #102 ; 0x66
478: e5832000 str r2, [r3]
47c: e51b300c ldr r3, [fp, #-12]
480: e5933000 ldr r3, [r3]
484: e2833018 add r3, r3, #24
488: e3a02b07 mov r2, #7168 ; 0x1c00
48c: e5832000 str r2, [r3]
490: e51b300c ldr r3, [fp, #-12]
494: e5933000 ldr r3, [r3]
498: e5932000 ldr r2, [r3]
49c: e3822040 orr r2, r2, #64 ; 0x40
4a0: e5832000 str r2, [r3]
4a4: e51b300c ldr r3, [fp, #-12]
4a8: e3a02000 mov r2, #0
4ac: e5832004 str r2, [r3, #4]
4b0: e51b3008 ldr r3, [fp, #-8]
4b4: e2833001 add r3, r3, #1
4b8: e50b3008 str r3, [fp, #-8]
4bc: e51b3008 ldr r3, [fp, #-8]
4c0: e3530003 cmp r3, #3
4c4: daffffb3 ble 398 <timer_init+0x18>
4c8: e1a00000 nop ; (mov r0, r0)
4cc: e1a00000 nop ; (mov r0, r0)
4d0: e28bd000 add sp, fp, #0
4d4: e49db004 pop {fp} ; (ldr fp, [sp], #4)
4d8: e12fff1e bx lr
4dc: 00000000 .word 0x00000000
4e0: 101e2000 .word 0x101e2000
4e4: 101e2020 .word 0x101e2020
4e8: 101e3000 .word 0x101e3000
4ec: 101e3020 .word 0x101e3020
000004f0 <timer_clearInterupt>:
4f0: e52db004 push {fp} ; (str fp, [sp, #-4]!)
4f4: e28db000 add fp, sp, #0
4f8: e24dd014 sub sp, sp, #20
4fc: e50b0010 str r0, [fp, #-16]
500: e51b3010 ldr r3, [fp, #-16]
504: e1a03183 lsl r3, r3, #3
508: e59f2028 ldr r2, [pc, #40] ; 538 <timer_clearInterupt+0x48>
50c: e0833002 add r3, r3, r2
510: e50b3008 str r3, [fp, #-8]
514: e51b3008 ldr r3, [fp, #-8]
518: e5933000 ldr r3, [r3]
51c: e283300c add r3, r3, #12
520: e3e02000 mvn r2, #0
524: e5832000 str r2, [r3]
528: e1a00000 nop ; (mov r0, r0)
52c: e28bd000 add sp, fp, #0
530: e49db004 pop {fp} ; (ldr fp, [sp], #4)
534: e12fff1e bx lr
538: 00000000 .word 0x00000000
0000053c <timer_handler>:
53c: e92d4800 push {fp, lr}
540: e28db004 add fp, sp, #4
544: e24dd010 sub sp, sp, #16
548: e50b0010 str r0, [fp, #-16]
54c: e51b3010 ldr r3, [fp, #-16]
550: e1a03183 lsl r3, r3, #3
554: e59f203c ldr r2, [pc, #60] ; 598 <timer_handler+0x5c>
558: e0833002 add r3, r3, r2
55c: e50b3008 str r3, [fp, #-8]
560: e51b3008 ldr r3, [fp, #-8]
564: e5933004 ldr r3, [r3, #4]
568: e2832001 add r2, r3, #1
56c: e51b3008 ldr r3, [fp, #-8]
570: e5832004 str r2, [r3, #4]
574: e51b0010 ldr r0, [fp, #-16]
578: ebfffffe bl 4f0 <timer_clearInterupt>
57c: e59f1018 ldr r1, [pc, #24] ; 59c <timer_handler+0x60>
580: e59f0018 ldr r0, [pc, #24] ; 5a0 <timer_handler+0x64>
584: ebfffffe bl 1c0 <uprints>
588: e1a00000 nop ; (mov r0, r0)
58c: e24bd004 sub sp, fp, #4
590: e8bd4800 pop {fp, lr}
594: e12fff1e bx lr
...
000005a4 <timer_start>:
5a4: e92d4800 push {fp, lr}
5a8: e28db004 add fp, sp, #4
5ac: e24dd010 sub sp, sp, #16
5b0: e50b0010 str r0, [fp, #-16]
5b4: e59f1044 ldr r1, [pc, #68] ; 600 <timer_start+0x5c>
5b8: e59f0044 ldr r0, [pc, #68] ; 604 <timer_start+0x60>
5bc: ebfffffe bl 1c0 <uprints>
5c0: e51b3010 ldr r3, [fp, #-16]
5c4: e1a03183 lsl r3, r3, #3
5c8: e59f2038 ldr r2, [pc, #56] ; 608 <timer_start+0x64>
5cc: e0833002 add r3, r3, r2
5d0: e50b3008 str r3, [fp, #-8]
5d4: e51b3008 ldr r3, [fp, #-8]
5d8: e5933000 ldr r3, [r3]
5dc: e2832008 add r2, r3, #8
5e0: e5922000 ldr r2, [r2]
5e4: e2833008 add r3, r3, #8
5e8: e3822080 orr r2, r2, #128 ; 0x80
5ec: e5832000 str r2, [r3]
5f0: e1a00000 nop ; (mov r0, r0)
5f4: e24bd004 sub sp, fp, #4
5f8: e8bd4800 pop {fp, lr}
5fc: e12fff1e bx lr
600: 00000010 .word 0x00000010
...
0000060c <timer_stop>:
60c: e52db004 push {fp} ; (str fp, [sp, #-4]!)
610: e28db000 add fp, sp, #0
614: e24dd014 sub sp, sp, #20
618: e50b0010 str r0, [fp, #-16]
61c: e51b3010 ldr r3, [fp, #-16]
620: e1a03183 lsl r3, r3, #3
624: e59f2028 ldr r2, [pc, #40] ; 654 <timer_stop+0x48>
628: e0833002 add r3, r3, r2
62c: e50b3008 str r3, [fp, #-8]
630: e51b3008 ldr r3, [fp, #-8]
634: e5933000 ldr r3, [r3]
638: e2833008 add r3, r3, #8
63c: e3a0207f mov r2, #127 ; 0x7f
640: e5832000 str r2, [r3]
644: e1a00000 nop ; (mov r0, r0)
648: e28bd000 add sp, fp, #0
64c: e49db004 pop {fp} ; (ldr fp, [sp], #4)
650: e12fff1e bx lr
654: 00000000 .word 0x00000000
00000658 <undef_handler>:
658: e92d4800 push {fp, lr}
65c: e28db004 add fp, sp, #4
660: e59f1014 ldr r1, [pc, #20] ; 67c <undef_handler+0x24>
664: e59f0014 ldr r0, [pc, #20] ; 680 <undef_handler+0x28>
668: ebfffffe bl 1c0 <uprints>
66c: e1a00000 nop ; (mov r0, r0)
670: e24bd004 sub sp, fp, #4
674: e8bd4800 pop {fp, lr}
678: e12fff1e bx lr
67c: 00000020 .word 0x00000020
680: 00000000 .word 0x00000000
00000684 <swi_handler>:
684: e92d4800 push {fp, lr}
688: e28db004 add fp, sp, #4
68c: e59f1014 ldr r1, [pc, #20] ; 6a8 <swi_handler+0x24>
690: e59f0014 ldr r0, [pc, #20] ; 6ac <swi_handler+0x28>
694: ebfffffe bl 1c0 <uprints>
698: e1a00000 nop ; (mov r0, r0)
69c: e24bd004 sub sp, fp, #4
6a0: e8bd4800 pop {fp, lr}
6a4: e12fff1e bx lr
6a8: 00000020 .word 0x00000020
6ac: 00000000 .word 0x00000000
000006b0 <prefetch_abort_handler>:
6b0: e92d4800 push {fp, lr}
6b4: e28db004 add fp, sp, #4
6b8: e59f1014 ldr r1, [pc, #20] ; 6d4 <prefetch_abort_handler+0x24>
6bc: e59f0014 ldr r0, [pc, #20] ; 6d8 <prefetch_abort_handler+0x28>
6c0: ebfffffe bl 1c0 <uprints>
6c4: e1a00000 nop ; (mov r0, r0)
6c8: e24bd004 sub sp, fp, #4
6cc: e8bd4800 pop {fp, lr}
6d0: e12fff1e bx lr
6d4: 00000020 .word 0x00000020
6d8: 00000000 .word 0x00000000
000006dc <data_abort_handler>:
6dc: e92d4800 push {fp, lr}
6e0: e28db004 add fp, sp, #4
6e4: e59f1014 ldr r1, [pc, #20] ; 700 <data_abort_handler+0x24>
6e8: e59f0014 ldr r0, [pc, #20] ; 704 <data_abort_handler+0x28>
6ec: ebfffffe bl 1c0 <uprints>
6f0: e1a00000 nop ; (mov r0, r0)
6f4: e24bd004 sub sp, fp, #4
6f8: e8bd4800 pop {fp, lr}
6fc: e12fff1e bx lr
700: 00000020 .word 0x00000020
704: 00000000 .word 0x00000000
00000708 <fiq_handler>:
708: e92d4800 push {fp, lr}
70c: e28db004 add fp, sp, #4
710: e59f1014 ldr r1, [pc, #20] ; 72c <fiq_handler+0x24>
714: e59f0014 ldr r0, [pc, #20] ; 730 <fiq_handler+0x28>
718: ebfffffe bl 1c0 <uprints>
71c: e1a00000 nop ; (mov r0, r0)
720: e24bd004 sub sp, fp, #4
724: e8bd4800 pop {fp, lr}
728: e12fff1e bx lr
72c: 00000020 .word 0x00000020
730: 00000000 .word 0x00000000
00000734 <copy_vector>:
734: e52db004 push {fp} ; (str fp, [sp, #-4]!)
738: e28db000 add fp, sp, #0
73c: e24dd00c sub sp, sp, #12
740: e59f3050 ldr r3, [pc, #80] ; 798 <copy_vector+0x64>
744: e50b3008 str r3, [fp, #-8]
748: e3a03000 mov r3, #0
74c: e50b300c str r3, [fp, #-12]
750: ea000007 b 774 <copy_vector+0x40>
754: e51b2008 ldr r2, [fp, #-8]
758: e2823004 add r3, r2, #4
75c: e50b3008 str r3, [fp, #-8]
760: e51b300c ldr r3, [fp, #-12]
764: e2831004 add r1, r3, #4
768: e50b100c str r1, [fp, #-12]
76c: e5922000 ldr r2, [r2]
770: e5832000 str r2, [r3]
774: e51b3008 ldr r3, [fp, #-8]
778: e59f201c ldr r2, [pc, #28] ; 79c <copy_vector+0x68>
77c: e1530002 cmp r3, r2
780: 3afffff3 bcc 754 <copy_vector+0x20>
784: e1a00000 nop ; (mov r0, r0)
788: e1a00000 nop ; (mov r0, r0)
78c: e28bd000 add sp, fp, #0
790: e49db004 pop {fp} ; (ldr fp, [sp], #4)
794: e12fff1e bx lr
...
000007a0 <kbd_init>:
7a0: e52db004 push {fp} ; (str fp, [sp, #-4]!)
7a4: e28db000 add fp, sp, #0
7a8: e24dd00c sub sp, sp, #12
7ac: e59f302c ldr r3, [pc, #44] ; 7e0 <kbd_init+0x40>
7b0: e50b3008 str r3, [fp, #-8]
7b4: e51b3008 ldr r3, [fp, #-8]
7b8: e3a02014 mov r2, #20
7bc: e5c32000 strb r2, [r3]
7c0: e51b3008 ldr r3, [fp, #-8]
7c4: e283300c add r3, r3, #12
7c8: e3a02008 mov r2, #8
7cc: e5c32000 strb r2, [r3]
7d0: e1a00000 nop ; (mov r0, r0)
7d4: e28bd000 add sp, fp, #0
7d8: e49db004 pop {fp} ; (ldr fp, [sp], #4)
7dc: e12fff1e bx lr
7e0: 10006000 .word 0x10006000
000007e4 <IRQ_handler>:
7e4: e92d4800 push {fp, lr}
7e8: e28db004 add fp, sp, #4
7ec: e24dd008 sub sp, sp, #8
7f0: e3a03000 mov r3, #0
7f4: e50b3008 str r3, [fp, #-8]
7f8: e59f10a4 ldr r1, [pc, #164] ; 8a4 <IRQ_handler+0xc0>
7fc: e59f00a4 ldr r0, [pc, #164] ; 8a8 <IRQ_handler+0xc4>
800: ebfffffe bl 1c0 <uprints>
804: e59f30a0 ldr r3, [pc, #160] ; 8ac <IRQ_handler+0xc8>
808: e5933000 ldr r3, [r3]
80c: e5933000 ldr r3, [r3]
810: e2833004 add r3, r3, #4
814: e5933000 ldr r3, [r3]
818: e3530000 cmp r3, #0
81c: 1a000001 bne 828 <IRQ_handler+0x44>
820: e3a00000 mov r0, #0
824: ebfffffe bl 53c <timer_handler>
828: e59f307c ldr r3, [pc, #124] ; 8ac <IRQ_handler+0xc8>
82c: e5933004 ldr r3, [r3, #4]
830: e5933000 ldr r3, [r3]
834: e2833004 add r3, r3, #4
838: e5933000 ldr r3, [r3]
83c: e3530000 cmp r3, #0
840: 1a000001 bne 84c <IRQ_handler+0x68>
844: e3a00001 mov r0, #1
848: ebfffffe bl 53c <timer_handler>
84c: e59f3058 ldr r3, [pc, #88] ; 8ac <IRQ_handler+0xc8>
850: e5933008 ldr r3, [r3, #8]
854: e5933000 ldr r3, [r3]
858: e2833004 add r3, r3, #4
85c: e5933000 ldr r3, [r3]
860: e3530000 cmp r3, #0
864: 1a000001 bne 870 <IRQ_handler+0x8c>
868: e3a00002 mov r0, #2
86c: ebfffffe bl 53c <timer_handler>
870: e59f3034 ldr r3, [pc, #52] ; 8ac <IRQ_handler+0xc8>
874: e593300c ldr r3, [r3, #12]
878: e5933000 ldr r3, [r3]
87c: e2833004 add r3, r3, #4
880: e5933000 ldr r3, [r3]
884: e3530000 cmp r3, #0
888: 1a000001 bne 894 <IRQ_handler+0xb0>
88c: e3a00003 mov r0, #3
890: ebfffffe bl 53c <timer_handler>
894: e1a00000 nop ; (mov r0, r0)
898: e24bd004 sub sp, fp, #4
89c: e8bd4800 pop {fp, lr}
8a0: e12fff1e bx lr
8a4: 00000030 .word 0x00000030
...
000008b0 <main>:
8b0: e92d4800 push {fp, lr}
8b4: e28db004 add fp, sp, #4
8b8: e24dd010 sub sp, sp, #16
8bc: ebfffffe bl 218 <fbuf_init>
8c0: ebfffffe bl 0 <uart_init>
8c4: ebfffffe bl 380 <timer_init>
8c8: ebfffffe bl 7a0 <kbd_init>
8cc: e3a03000 mov r3, #0
8d0: e50b3008 str r3, [fp, #-8]
8d4: ea00000b b 908 <main+0x58>
8d8: e51b3008 ldr r3, [fp, #-8]
8dc: e1a03183 lsl r3, r3, #3
8e0: e59f20dc ldr r2, [pc, #220] ; 9c4 <main+0x114>
8e4: e0832002 add r2, r3, r2
8e8: e59f10d8 ldr r1, [pc, #216] ; 9c8 <main+0x118>
8ec: e51b3008 ldr r3, [fp, #-8]
8f0: e7812103 str r2, [r1, r3, lsl #2]
8f4: e51b0008 ldr r0, [fp, #-8]
8f8: ebfffffe bl 5a4 <timer_start>
8fc: e51b3008 ldr r3, [fp, #-8]
900: e2833001 add r3, r3, #1
904: e50b3008 str r3, [fp, #-8]
908: e51b3008 ldr r3, [fp, #-8]
90c: e3530003 cmp r3, #3
910: dafffff0 ble 8d8 <main+0x28>
914: e59f10b0 ldr r1, [pc, #176] ; 9cc <main+0x11c>
918: e59f00b0 ldr r0, [pc, #176] ; 9d0 <main+0x120>
91c: ebfffffe bl 1c0 <uprints>
920: e59f309c ldr r3, [pc, #156] ; 9c4 <main+0x114>
924: e5931004 ldr r1, [r3, #4]
928: e59f30a4 ldr r3, [pc, #164] ; 9d4 <main+0x124>
92c: e0c32391 smull r2, r3, r1, r3
930: e1a021c3 asr r2, r3, #3
934: e1a03fc1 asr r3, r1, #31
938: e0422003 sub r2, r2, r3
93c: e1a03002 mov r3, r2
940: e1a03183 lsl r3, r3, #3
944: e0433002 sub r3, r3, r2
948: e1a03183 lsl r3, r3, #3
94c: e0433002 sub r3, r3, r2
950: e1a03103 lsl r3, r3, #2
954: e0412003 sub r2, r1, r3
958: e1a03002 mov r3, r2
95c: e54b3009 strb r3, [fp, #-9]
960: e55b3009 ldrb r3, [fp, #-9]
964: e2833037 add r3, r3, #55 ; 0x37
968: e20330ff and r3, r3, #255 ; 0xff
96c: e1a01003 mov r1, r3
970: e59f0058 ldr r0, [pc, #88] ; 9d0 <main+0x120>
974: ebfffffe bl e4 <uputc>
978: e55b3009 ldrb r3, [fp, #-9]
97c: e383386e orr r3, r3, #7208960 ; 0x6e0000
980: e3833001 orr r3, r3, #1
984: e50b3010 str r3, [fp, #-16]
988: e51b3010 ldr r3, [fp, #-16]
98c: e3a02064 mov r2, #100 ; 0x64
990: e3a0100a mov r1, #10
994: e3a0000a mov r0, #10
998: ebfffffe bl 2b8 <draw_box>
99c: e59f3020 ldr r3, [pc, #32] ; 9c4 <main+0x114>
9a0: e5933004 ldr r3, [r3, #4]
9a4: e3530000 cmp r3, #0
9a8: 0affffdc beq 920 <main+0x70>
9ac: e3a03b32 mov r3, #51200 ; 0xc800
9b0: e3a02032 mov r2, #50 ; 0x32
9b4: e3a010fa mov r1, #250 ; 0xfa
9b8: e3a000c8 mov r0, #200 ; 0xc8
9bc: ebfffffe bl 2b8 <draw_box>
9c0: eaffffd6 b 920 <main+0x70>
...
9cc: 0000003c .word 0x0000003c
9d0: 00000000 .word 0x00000000
9d4: 094f2095 .word 0x094f2095
also my linker script:
ENTRY(start)
SECTIONS{
. = 0x10000;
.text : {*(.text)}
.data : {*(.data)}
.bss : {*(.bss)}
. =ALIGN(8);
. =. + 0x1000;
stack_top = .;
. = . + 0x1000;
irq_stack_top = .;
}
So I do not have a complete example but something looks wrong, really wrong that you will need to sort out. And maybe you are already through all of these basic steps to get to this point.
qemu-system-arm -M versatilepb -m 128M -kernel notmain.bin
Implies a binary memory image file as in objcopy -O binary is being used. And there is no addressing information, so some default built into that machine or simulation is being used. What is that address....
strap.s
mov sp,#0x10000
bl notmain
b .
.globl GETPC
GETPC:
mov r0,pc
bx lr
.globl PUT32
PUT32:
str r1,[r0]
bx lr
notmain.c
void PUT32 ( unsigned int, unsigned int );
unsigned int GETPC ( void );
#define UART_BASE 0x101F1000
#define UARTDR (UART_BASE+0x000)
static void uart_send ( unsigned int x )
{
PUT32(UARTDR,x);
}
static void hexstrings ( unsigned int d )
{
unsigned int rb;
unsigned int rc;
rb=32;
while(1)
{
rb-=4;
rc=(d>>rb)&0xF;
if(rc>9) rc+=0x37; else rc+=0x30;
uart_send(rc);
if(rb==0) break;
}
uart_send(0x20);
}
static void hexstring ( unsigned int d )
{
hexstrings(d);
uart_send(0x0D);
uart_send(0x0A);
}
int notmain ( void )
{
hexstring(GETPC());
return(0);
}
uart address culled from the source code to qemu. so far I find you can cheat and just write to the tx buffer, it does not actually emulate the time it takes to send out a character and overflow a fifo, etc. So I cheat.
/* memmap */
MEMORY
{
ram : ORIGIN = 0x00000000, LENGTH = 32K
}
SECTIONS
{
.text : { *(.text*) } > ram
.bss : { *(.text*) } > ram
}
build
arm-none-eabi-as --warn --fatal-warnings -march=armv4t strap.s -o strap.o
arm-none-eabi-gcc -c -Wall -O2 -ffreestanding -march=armv4t notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles strap.o notmain.o -T memmap -o notmain.elf
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy notmain.elf -O binary notmain.bin
examine output
Disassembly of section .text:
00000000 <GETPC-0xc>:
0: e3a0d801 mov sp, #65536 ; 0x10000
4: eb000004 bl 1c <notmain>
8: eafffffe b 8 <GETPC-0x4>
0000000c <GETPC>:
c: e1a0000f mov r0, pc
10: e12fff1e bx lr
00000014 <PUT32>:
14: e5801000 str r1, [r0]
18: e12fff1e bx lr
0000001c <notmain>:
1c: e92d4070 push {r4, r5, r6, lr}
20: ebfffff9 bl c <GETPC>
24: e3a04020 mov r4, #32
my entry point is where I want it. I am not loading an elf I am loading a binary image. If I wanted the entry point to be different and load an elf it may be possible that using ENTRY() in the linker script then having the entry point wherever might work.
qemu-system-arm -M versatilepb -m 128M -kernel notmain.bin
then view the serial0 output of 00010014 so they are loading us at 0x10000 so change memmap
ram : ORIGIN = 0x00010000, LENGTH = 32K
Now your linker script implies it should have put your code at 0x10000 but
clearly it has not based on your disassembly, so how are you running anything at all. Also your entry point using a binary image is not the bootstrap it is not the first instructions you want to be executing. maybe you disassembled an object not the final binary?
So for fun before changing the memory map to 0x10000 if I instead
qemu-system-arm -M versatilepb -m 128M -kernel notmain.elf
Then I get 00000014 on the output. it used the address defined in the elf file.
If I add this
b .
.globl _start
_start:
mov sp,#0x10000
bl notmain
b .
and this
/* memmap */
ENTRY(_start)
MEMORY
{
ram : ORIGIN = 0x00000000, LENGTH = 32K
}
SECTIONS
{
.text : { *(.text*) } > ram
.bss : { *(.text*) } > ram
}
and execute the elf I do get output of 00000018 so it is entering at the entry point not the first word of the loadable image.
run the .bin and you get no serial output as expected.
Change memmap to 0x10000 and run the elf you get 0x10018 as expected.
So that was a simple way to see how qemu loads our program.
so same build and linker script (with the 0x10000)
.globl _start
_start:
ldr pc,reset_handler
ldr pc,undefined_handler
ldr pc,swi_handler
ldr pc,prefetch_handler
ldr pc,data_handler
ldr pc,unused_handler
ldr pc,irq_handler
ldr pc,fiq_handler
reset_handler: .word reset
undefined_handler: .word hang
swi_handler: .word swi
prefetch_handler: .word hang
data_handler: .word hang
unused_handler: .word hang
irq_handler: .word hang
fiq_handler: .word hang
reset:
mov r0,#0x10000
mov r1,#0x00000
ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9}
stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9}
ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9}
stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9}
;# FIQ 110 10001
msr cpsr_c,#0xD1
mov sp,#0x1000
;# IRQ 110 10010
msr cpsr_c,#0xD2
mov sp,#0x2000
;# SVC 110 10011
msr cpsr_c,#0xD3
mov sp,#0x3000
;# ABT 110 10111
msr cpsr_c,#0xD7
mov sp,#0x4000
;# UND 110 11011
msr cpsr_c,#0xDB
mov sp,#0x5000
;# SYS 110 11111
msr cpsr_c,#0xDF
mov sp,#0x6000
;# SVC 110 10011
msr cpsr_c,#0xD3
bl notmain
hang:
b hang
swi:
push {r4-r12,lr}
bl swi_main
pop {r4-r12,lr}
movs pc,lr
.globl DO_SWI
DO_SWI:
push {lr}
svc 0
pop {lr}
bx lr
.globl GO_USER
GO_USER:
;# USER 110 10000
msr cpsr_c,#0xD0
bl gouser
b .
gouser:
bx r0
.globl GETMODE
GETMODE:
mrs r0,cpsr
bx lr
.globl GETPC
GETPC:
mov r0,pc
bx lr
.globl GETSP
GETSP:
mov r0,sp
bx lr
.globl PUT32
PUT32:
str r1,[r0]
bx lr
.globl GET32
GET32:
ldr r0,[r0]
bx lr
and
void PUT32 ( unsigned int, unsigned int );
unsigned int GET32 ( unsigned int );
unsigned int GETPC ( void );
unsigned int GETSP ( void );
unsigned int GETMODE ( void );
unsigned int GO_USER ( unsigned int );
unsigned int DO_SWI ( unsigned int, unsigned int, unsigned int, unsigned int );
#define UART_BASE 0x101F1000
#define UARTDR (UART_BASE+0x000)
#define UARTFR (UART_BASE+0x018)
static void uart_send ( unsigned int x )
{
while(1)
{
if(GET32(UARTFR)&(1<<7)) break;
}
PUT32(UARTDR,x);
}
static void hexstrings ( unsigned int d )
{
unsigned int rb;
unsigned int rc;
rb=32;
while(1)
{
rb-=4;
rc=(d>>rb)&0xF;
if(rc>9) rc+=0x37; else rc+=0x30;
uart_send(rc);
if(rb==0) break;
}
uart_send(0x20);
}
static void hexstring ( unsigned int d )
{
hexstrings(d);
uart_send(0x0D);
uart_send(0x0A);
}
unsigned int swi_main ( unsigned int a, unsigned int b, unsigned int c, unsigned int d )
{
hexstring(0xAABBCCDD);
switch(a)
{
case 0:
{
return(~b);
}
case 1:
{
return(GETMODE());
}
}
return(0);
}
void user_main ( void )
{
hexstring(GETMODE());
hexstring(GETSP());
hexstring(DO_SWI(0,0x1234,0,0));
hexstring(DO_SWI(1,0x1234,0,0));
}
int notmain ( void )
{
hexstring(GETMODE());
hexstring(GETSP());
GO_USER((unsigned int)user_main);
return(0);
}
get even a trivial swi in place first before attempting an interrupt. getting the exception table in place, the banked stack registers, etc. seems trivial but even with experience those things bite you and you end up chasing the wrong thing.
400001D3
00002FF8
200001D0
00005FF8
AABBCCDD
FFFFEDCB
AABBCCDD
600001D3
this was a bit overkill with mode changes and such, but it still has the swi handler in the right place. The code is linked for
notmain.elf: file format elf32-littlearm
Disassembly of section .text:
00010000 <_start>:
10000: e59ff018 ldr pc, [pc, #24] ; 10020 <reset_handler>
10004: e59ff018 ldr pc, [pc, #24] ; 10024 <undefined_handler>
10008: e59ff018 ldr pc, [pc, #24] ; 10028 <swi_handler>
1000c: e59ff018 ldr pc, [pc, #24] ; 1002c <prefetch_handler>
10010: e59ff018 ldr pc, [pc, #24] ; 10030 <data_handler>
10014: e59ff018 ldr pc, [pc, #24] ; 10034 <unused_handler>
10018: e59ff018 ldr pc, [pc, #24] ; 10038 <irq_handler>
1001c: e59ff018 ldr pc, [pc, #24] ; 1003c <fiq_handler>
00010020 <reset_handler>:
10020: 00010040 andeq r0, r1, r0, asr #32
00010024 <undefined_handler>:
10024: 00010090 muleq r1, r0, r0
packing the exception table with its pc-relative addresses and letting the toolchain do all the work of sorting out addresses for you, you can then simply copy it to 0x00000000 from 0x10000. It is probably fine but in your case I would at least put some level of alignment before your table, something makes me want to think it wants to be aligned. However you wish to copy it is your deal, I would not use C in a bootstrap, the habit creates problems from time to time that are easily avoided.
Knowing what we know of course if we linked for address 0x00000000 and used the elf file then we do not have to copy/move the exception table. It lands in the right place on load.
Newer cores have a VTOR register and you can simply choose a different exception or vector table address, but it does need to have a level of alignment that you cannot forget.
I did not go and research this timer, but I assume long before you attempted an interrupt you wrote very many throwaway programs that used polling to fully understand the timer and how to clear its interrupt, etc? Depending on the chip (not necessarily core) then there may also be arm side registers you can poll, disable interrupts into the core, poll the gvic or vpic or whatever it is called and see the interrupt hit the edge of the core, be able to turn it off, etc. Then.....enable it into the core now that you have mastered that peripheral. Sometimes leaving nothing left to work on, for some cores though there is some interrupt stuff that can only be done in an isr (how to detect and clear the interrupt source) this virtual machine predates that by a long time though, so no worries there.
so...
If that is your linker script then why is your output zero based, and why is the uart function up front and not the bootstrap entry point? If that is the disassembly of the final binary then there are all kinds of problems going on there.
I was seeing this as baremetal but forgetting qemu is loading linux-like so at some address like 0x8000, 0x10000, or 0x80000 are some examples, so yes you either need a core with a VTOR or copy the exception table over, and letting the tools build the addresses and pc-relative loads is the way to go. That copy is probably fine if you are actually booting right and executing it.
Then have you completely mastered that peripheral?
This is an emulated core so it may resemble one/some of the products from arm but remember they are not all identical some come with interrupt controllers some do not, some folks like the raspi folks disable that interrupt controller, etc. The base address of add on peripherals for real arm cores is based on the chip vendor not arm. Etc....Best to dig through the source code for the specific machine emulation and see what it is doing to truly get a qemu machine to work.
So maybe you have done all of these things and it still does not work. The question as written has some issues, the disassembly does not make sense for example. Need to resolve that. What if you try with an elf file first and an entry point then do the extra work to be able to run without the elf file and the bin file instead. Do not re-write but add more content to the question if you need further help. Unless someone else sees the issue with what has been presented.

ARM64 Backtrace from link register

I am currently trying to get backtrace based on stack pointer and link register on ARM64 device using C program.
Below is example of objdump
bar() calls foo() with 240444: ebfffd68 bl 23f9ec <foo##Base>
I can get link register (lr) and from that getting 23f9ec, save it to backtrace list as last routine.
My question: From below assembly code with current lr 0023f9ec <foo##Base>:, how to calculate to get previous routine with lr is 0023fe14 <bar##Base> using C language?
here is my implementation, but getting wrong previous lr
int bt(void** backtrace, int max_size) {
unsigned long* sp = __get_SP();
unsigned long* ra = __get_LR();
int* funcbase = (int*)(int)&bt;
int spofft = (short)((*funcbase));
sp = (char*)sp-spofft;
unsigned long* wra = (unsigned long*)ra;
int spofft;
int depth = 0;
while(ra) {
wra = ra;
while((*wra >> 16) != 0xe92d) {
wra--;
}
if(wra == 0)
return 0;
spofft = (short)(*wra & 0xffff);
if(depth < max_size)
backtrace[depth] = ra;
else
break;
ra =(unsigned long *)((unsigned long)ra + spofft);
sp =(unsigned long *)((unsigned long)sp + spofft);
depth++;
}
return 1;
}
0023f9ec <foo##Base>:
23f9ec: e92d42f3 push {r0, r1, r4, r5, r6, r7, r9, lr}
23f9f0: e1a09001 mov r9, r1
23f9f4: e1a07000 mov r7, r0
23f9f8: ebfffff9 bl 23f9e4 <__get_SP##Base>
23f9fc: e59f4060 ldr r4, [pc, #96] ; 23fa64 <foo##Base+0x78>
23fa00: e08f4004 add r4, pc, r4
23fa04: e1a05000 mov r5, r0
23fa08: ebfffff3 bl 23f9dc <__get_LR##Base>
23fa0c: e59f3054 ldr r3, [pc, #84] ; 23fa68 <foo##Base+0x7c>
23fa10: e3002256 movw r2, #598 ; 0x256
23fa14: e59f1050 ldr r1, [pc, #80] ; 23fa6c <foo##Base+0x80>
23fa18: e7943003 ldr r3, [r4, r3]
23fa1c: e08f1001 add r1, pc, r1
23fa20: e5934000 ldr r4, [r3]
23fa24: e1a03005 mov r3, r5
23fa28: e6bf4074 sxth r4, r4
23fa2c: e58d4004 str r4, [sp, #4]
23fa30: e1a06000 mov r6, r0
23fa34: e58d0000 str r0, [sp]
23fa38: e59f0030 ldr r0, [pc, #48] ; 23fa70 <foo##Base+0x84>
23fa3c: e08f0000 add r0, pc, r0
23fa40: ebfd456d bl 190ffc <printf#plt>
23fa44: e1a03009 mov r3, r9
23fa48: e1a02007 mov r2, r7
23fa4c: e1a01006 mov r1, r6
23fa50: e0640005 rsb r0, r4, r5
23fa54: ebffff70 bl 23f81c <get_prev_sp_ra2##Base>
23fa58: e3a00000 mov r0, #0
23fa5c: e28dd008 add sp, sp, #8
23fa60: e8bd82f0 pop {r4, r5, r6, r7, r9, pc}
23fa64: 003d5be0 eorseq r5, sp, r0, ror #23
23fa68: 000026c8 andeq r2, r0, r8, asr #13
23fa6c: 002b7ba6 eoreq r7, fp, r6, lsr #23
23fa70: 002b73e5 eoreq r7, fp, r5, ror #7
0023fe14 <bar##Base>:
23fe14: e92d4ef0 push {r4, r5, r6, r7, r9, sl, fp, lr}
23fe18: e24dde16 sub sp, sp, #352 ; 0x160
23fe1c: e59f76a8 ldr r7, [pc, #1704] ; 2404cc <bar##Base+0x6b8>
23fe20: e1a04000 mov r4, r0
23fe24: e59f66a4 ldr r6, [pc, #1700] ; 2404d0 <bar##Base+0x6bc>
23fe28: e1a03000 mov r3, r0
23fe2c: e59f26a0 ldr r2, [pc, #1696] ; 2404d4 <bar##Base+0x6c0>
23fe30: e08f7007 add r7, pc, r7
23fe34: e08f6006 add r6, pc, r6
23fe38: e3a00000 mov r0, #0
23fe3c: e08f2002 add r2, pc, r2
23fe40: e1a05001 mov r5, r1
23fe44: e3a01003 mov r1, #3
23fe48: e59f9688 ldr r9, [pc, #1672] ; 2404d8 <bar##Base+0x6c4>
.....................................................................
24043c: e3a0100f mov r1, #15
240440: e1a0000a mov r0, sl
240444: ebfffd68 bl 23f9ec <foo##Base>
240448: e59f2108 ldr r2, [pc, #264] ; 240558 <bar##Base+0x744>
24044c: e3a01003 mov r1, #3
240450: e08f2002 add r2, pc, r2
240454: e1a05000 mov r5, r0
240458: e1a03000 mov r3, r0
24045c: e3a00000 mov r0, #0
I don't think there's an easy way to do this.
Normally the register ABI of any operating system contains a "frame pointer" register. For example, on Apple's armv7 ABI, this is r7:
0x10006fc0 b0b5 push {r4, r5, r7, lr}
0x10006fc2 02af add r7, sp, 8
0x10006fc4 0448 ldr r0, [0x10006fd8]
0x10006fc6 d0e90c45 ldrd r4, r5, [r0, 0x30]
0x10006fca 0020 movs r0, 0
0x10006fcc fff7a6ff bl 0x10006f1c
0x10006fd0 0019 adds r0, r0, r4
0x10006fd2 6941 adcs r1, r5
0x10006fd4 b0bd pop {r4, r5, r7, pc}
If you dereference r7 there, you get to a pair of pointers, the second of which is lr, and the first of which is the r7 of the calling function, allowing you to repeat this process until you reach the bottom of the stack.
Judging by the assembly you posted, the codebase you're looking at doesn't have that. This means that the only way to obtain the return address is the same way that the code itself does: step forward through each instruction and parse/interpret them until you reach something that loads into pc. This is of course imperfect, since there may be functions in your call stack that do not ever return, but there's not much you can do about that.
It may be tempting to search backwards instead, and while you can do a heuristic approach and probably reach quite reasonable results with it, that is even less reliable than searching forward, since you have absolutely no way of telling whether you arrived at address X by stepping forward from the previous instruction or by explicitly jumping there from somewhere else.

What could be the possible reason that an ARM register gets polluted?

Recently I ran into this strange issue(Thumb2 instr-set). Say I have following code:
000a8948 <some_func>:
a8948: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
a894c: 460f mov r7, r1
a894e: f8df 8260 ldr.w r8, [pc, #608]
a8952: 4606 mov r6, r0 --> r0 shows b89a8408 in backtrace
a8954: 4b97 ldr r3, [pc, #604]
a8956: f100 0410 add.w r4, r0, #16 --> only place r4 gets assigned, but it can't be 0.
a895a: 44f8 add r8, pc
a895c: f04f 0900 mov.w r9, #0
a8960: ed2d 8b04 vpush {d8-d9}
a8964: f858 1003 ldr.w r1, [r8, r3]
a8968: b095 sub sp, #84 ; 0x54
a896a: f8df b24c ldr.w fp, [pc, #588]
a896e: ad0c add r5, sp, #48
a8970: f8df c248 ldr.w ip, [pc, #584]
a8974: f8df a248 ldr.w sl, [pc, #584]
a8978: ed9f 8b8b vldr d8, [pc, #556]
a897c: 680a ldr r2, [r1, #0]
a897e: 44fb add fp, pc
a8980: 44fc add ip, pc
a8982: 44fa add sl, pc
a8984: 9107 str r1, [sp, #28]
a8986: 9213 str r2, [sp, #76]
a8988: 6823 ldr r3, [r4, #0] // ERR: SIGSEGV happens, code 1 (SEGV_MAPPER), fault addr 0x0
So when this issue happens, r4 turned to value 0, what I cannot figure out is that how r4 gets polluted, given it only be assigned to r0+16 at line a8956? Could it be that Neon instructions write r4 somehow?

arm c code disasembly confusing,

I have below the code:
struct inner{
uint32_t a;
uint32_t b;
};
struct outer{
struct inner *in;
};
void test_func(struct outer *o)
{
printh(o->in->b);
}
printh simple displays the value in hexformat.
The code is complied with the following flags -DSMP -marm -mcpu=cortex-a15
The assembly generated is as follows:
f0001cc0 <test_func>:
f0001cc0: e92d4800 push {fp, lr}
f0001cc4: e28db004 add fp, sp, #4
f0001cc8: e24dd008 sub sp, sp, #8
f0001ccc: e50b0008 str r0, [fp, #-8]
f0001cd0: e51b3008 ldr r3, [fp, #-8]
f0001cd4: e5933000 ldr r3, [r3]
f0001cd8: e5933004 ldr r3, [r3, #4]
f0001cdc: e1a00003 mov r0, r3
f0001ce0: ebfffb04 bl f00008f8 <printh>
f0001ce4: e24bd004 sub sp, fp, #4
f0001ce8: e8bd8800 pop {fp, pc}
With this code I get a data abort on f0001cd8 as r3 was loaded 0 in f0001cd4. But r3 was loaded with the address of o correctly in f0001cd4.
All I have is a simple line. I dont seem to understand why the following instruction is generated
f0001cd4: e5933000 ldr r3, [r3]
Because of this I am getting a data abort.
f0001cc0 <test_func>:
f0001cc0: e92d4800 push {fp, lr} ;\
f0001cc4: e28db004 add fp, sp, #4 ;> create stack frame
f0001cc8: e24dd008 sub sp, sp, #8 ;/
f0001ccc: e50b0008 str r0, [fp, #-8] ; save first arg (o) in stack
f0001cd0: e51b3008 ldr r3, [fp, #-8] ; load o
f0001cd4: e5933000 ldr r3, [r3] ; load o->in
f0001cd8: e5933004 ldr r3, [r3, #4] ; load o->in->b
f0001cdc: e1a00003 mov r0, r3 ; use as first arg to next fn
f0001ce0: ebfffb04 bl f00008f8 <printh> ; call printh
f0001ce4: e24bd004 sub sp, fp, #4 ;\
f0001ce8: e8bd8800 pop {fp, pc} ;/ destroy stack frame
The above (obviously compiled with no optimization) code is first loading o->in, and then o->in->b. o->in comes up at 0, which means that you haven't allocated memory for it.

Variable length arrays in C, how are they compiled

I have some given code that uses variable length arrays on the stack in C. I cannot easily change that code to use malloced buffers on the heap, since I am working on some stuff where I have no operating system support for dynamic memory. However when I test my method the stack actually get's smashed instead (i.e. the SP get's set to a completely bogus address). To figure out what is going on I had a look at the assembly and I was completely confused by the compiler output.
I am running the code on a pandaboard ES (OMAP4460 ARM processor).
In order to test how variable size arrays on the stack are actually compiled, I produced a simple working test program. However again the code was much too confusing for me to understand.
Here is what I do not understand:
When I compile a simple function:
int test_method(size_t i)
{
unsigned char buffer[10];
return -1;
}
I get some very simple assembler code:
80003a68 <test_method>:
80003a68: b480 push {r7} ; store frame pointer
80003a6a: b087 sub sp, #28 ; make stack frame (size 28)
80003a6c: af00 add r7, sp, #0 ; set frame pointer
80003a6e: 6078 str r0, [r7, #4]; store parameter on stack
80003a70: f04f 0300 mov.w r3, #0 ; load return value
80003a74: 4618 mov r0, r3 ; put return value in return register
80003a76: f107 071c add.w r7, r7, #28 ; destroy stack frame
80003a7a: 46bd mov sp, r7 ; ...
80003a7c: bc80 pop {r7} ; pop stored frame pointer
80003a7e: 4770 bx lr ; return
But when I try this with a variable size array using the following code:
int test_method(size_t i)
{
unsigned char buffer[i];
return 0;
}
I get this assembly:
80003a68 <test_method>:
80003a68: e92d 03f0 stmdb sp!, {r4, r5, r6, r7, r8, r9}
80003a6c: b084 sub sp, #16
80003a6e: af00 add r7, sp, #0
80003a70: 6078 str r0, [r7, #4]
80003a72: 4669 mov r1, sp
80003a74: 460e mov r6, r1
80003a76: f8d7 c004 ldr.w ip, [r7, #4]
80003a7a: 4661 mov r1, ip
80003a7c: f101 31ff add.w r1, r1, #4294967295 ; 0xffffffff
80003a80: 60b9 str r1, [r7, #8]
80003a82: 4660 mov r0, ip
80003a84: f04f 0100 mov.w r1, #0
80003a88: f04f 38ff mov.w r8, #4294967295 ; 0xffffffff
80003a8c: f04f 090f mov.w r9, #15
80003a90: ea00 0008 and.w r0, r0, r8
80003a94: ea01 0109 and.w r1, r1, r9
80003a98: ea4f 7850 mov.w r8, r0, lsr #29
80003a9c: ea4f 05c1 mov.w r5, r1, lsl #3
80003aa0: ea48 0505 orr.w r5, r8, r5
80003aa4: ea4f 04c0 mov.w r4, r0, lsl #3
80003aa8: f04f 30ff mov.w r0, #4294967295 ; 0xffffffff
80003aac: f04f 010f mov.w r1, #15
80003ab0: ea04 0400 and.w r4, r4, r0
80003ab4: ea05 0501 and.w r5, r5, r1
80003ab8: 4660 mov r0, ip
80003aba: f04f 0100 mov.w r1, #0
80003abe: f04f 34ff mov.w r4, #4294967295 ; 0xffffffff
80003ac2: f04f 050f mov.w r5, #15
80003ac6: ea00 0004 and.w r0, r0, r4
80003aca: ea01 0105 and.w r1, r1, r5
80003ace: ea4f 7450 mov.w r4, r0, lsr #29
80003ad2: ea4f 03c1 mov.w r3, r1, lsl #3
80003ad6: ea44 0303 orr.w r3, r4, r3
80003ada: ea4f 02c0 mov.w r2, r0, lsl #3
80003ade: f04f 30ff mov.w r0, #4294967295 ; 0xffffffff
80003ae2: f04f 010f mov.w r1, #15
80003ae6: ea02 0200 and.w r2, r2, r0
80003aea: ea03 0301 and.w r3, r3, r1
80003aea: ea03 0301 and.w r3, r3, r1
80003aee: 4663 mov r3, ip
80003af0: f103 0307 add.w r3, r3, #7
80003af4: f103 0307 add.w r3, r3, #7
80003af8: ea4f 03d3 mov.w r3, r3, lsr #3
80003afc: ea4f 03c3 mov.w r3, r3, lsl #3
80003b00: ebad 0d03 sub.w sp, sp, r3
80003b04: 466b mov r3, sp
80003b06: f103 0307 add.w r3, r3, #7
80003b0a: ea4f 03d3 mov.w r3, r3, lsr #3
80003b0e: ea4f 03c3 mov.w r3, r3, lsl #3
80003b12: 60fb str r3, [r7, #12]
80003b14: f04f 0300 mov.w r3, #0
80003b18: 46b5 mov sp, r6
80003b1a: 4618 mov r0, r3
80003b1c: f107 0710 add.w r7, r7, #16
80003b20: 46bd mov sp, r7
80003b22: e8bd 03f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9}
80003b26: 4770 bx lr
Where does all this additional logic come frome? I would have thought, that it would have been enough to just enlarge the stack frame by the size i (passed in r0), maybe with an addition of some extra code to keep the alignment. But why are all these additional registers written with 0xffffffff and #15. I cannot really make any sense of this assembly the compiler is giving me.
This is not really an answer just collecting more info that doesnt fit in a comment
typedef unsigned int size_t;
int test_method1(size_t i)
{
unsigned char buffer[10];
return -1;
}
int test_method2(size_t i)
{
unsigned char buffer[i];
return 0;
}
arm-none-eabi-gcc -O2 -c tm1.c -o tm1.o
arm-none-eabi-objdump -D tm1.o
basically optimizes everything away
00000000 <test_method1>:
0: e3e00000 mvn r0, #0
4: e12fff1e bx lr
00000008 <test_method2>:
8: e3a00000 mov r0, #0
c: e12fff1e bx lr
although bad code this should get the compiler to not optimize everything away
typedef unsigned int size_t;
unsigned char *test_method1(size_t i, size_t j)
{
unsigned char buffer[10];
return(&buffer[j]);
}
unsigned char *test_method2(size_t i, size_t j)
{
unsigned char buffer[i];
return(&buffer[j]);
}
00000000 <test_method1>:
0: e24dd010 sub sp, sp, #16
4: e28d3004 add r3, sp, #4
8: e0830001 add r0, r3, r1
c: e28dd010 add sp, sp, #16
10: e12fff1e bx lr
00000014 <test_method2>:
14: e92d0808 push {r3, fp}
18: e2800007 add r0, r0, #7
1c: e3c00007 bic r0, r0, #7
20: e28db004 add fp, sp, #4
24: e04dd000 sub sp, sp, r0
28: e08d0001 add r0, sp, r1
2c: e24bd004 sub sp, fp, #4
30: e8bd0808 pop {r3, fp}
34: e12fff1e bx lr
And it did and I think it perhaps answered your question. How the compiler handles arrays that are variable length is that in this case it did math on the stack pointer in the amount of the size of the array, basically allocating the dynamic array on the stack as you would expect. For the static sized array the math done on the stack was a static number not a passed in parameter.

Resources