When i try to call a java/soap web service from iOS (objective c) using AFNetworking, after many times I get this error: "EXC_BAD_ACCESS"
on 0x71d678: ldr r0, [r4, #0x68].
But I noticed that if on iPhone (particularly iphone 6 or in generally on iOS8) I disable WIFI the error disappeared
I post the assembly code
libdispatch.dylib`_dispatch_timers_run:
0x71d5f0: push {r4, r5, r6, r7, lr}
0x71d5f2: add r7, sp, #0xc
0x71d5f4: push.w {r8, r10, r11}
0x71d5f8: sub sp, #0x18
0x71d5fa: movs r6, #0x0
0x71d5fc: str r0, [sp]
0x71d5fe: movw r0, #0xa83e
0x71d602: movt r0, #0x1
0x71d606: add r0, pc
0x71d608: add.w r1, r0, r6, lsl #6
0x71d60c: ldr r0, [r1, #8]!
0x71d610: str r1, [sp, #0x14]
0x71d612: cmp r0, #0x0
0x71d614: beq.w 0x71d776 ; _dispatch_timers_run + 390
0x71d618: ubfx r4, r6, #0x2, #0x1
0x71d61c: ldr r5, [sp]
0x71d61e: cbz r5, 0x71d632 ; _dispatch_timers_run + 66
0x71d620: ldr.w r0, [r5, r4, lsl #3]
0x71d624: str r0, [sp, #0x10]
0x71d626: cbz r0, 0x71d632 ; _dispatch_timers_run + 66
0x71d628: add.w r0, r5, r4, lsl #3
0x71d62c: ldr r0, [r0, #0x4]
0x71d62e: str r0, [sp, #0xc]
0x71d630: b 0x71d664 ; _dispatch_timers_run + 116
0x71d632: cmp r4, #0x0
0x71d634: bne 0x71d63c ; _dispatch_timers_run + 76
0x71d636: bl 0x70df20 ; _dispatch_get_nanoseconds
0x71d63a: b 0x71d648 ; _dispatch_timers_run + 88
0x71d63c: cmp r4, #0x1
0x71d63e: str r0, [sp, #0x10]
0x71d640: str r0, [sp, #0xc]
0x71d642: bne 0x71d64c ; _dispatch_timers_run + 92
0x71d644: blx 0x72b380 ; symbol stub for: mach_absolute_time
0x71d648: str r0, [sp, #0x10]
0x71d64a: str r1, [sp, #0xc]
0x71d64c: cbz r5, 0x71d664 ; _dispatch_timers_run + 116
0x71d64e: ldr r0, [sp, #0x10]
0x71d650: ldr r1, [sp, #0xc]
0x71d652: str.w r0, [r5, r4, lsl #3]
0x71d656: add.w r0, r5, r4, lsl #3
0x71d65a: str r1, [r0, #0x4]
0x71d65c: b 0x71d664 ; _dispatch_timers_run + 116
0x71d65e: mov r0, r4
0x71d660: bl 0x71c5bc ; _dispatch_timers_update
0x71d664: ldr r0, [sp, #0x14]
0x71d666: ldr.w r10, [r0]
0x71d66a: cmp.w r10, #0x0
0x71d66e: beq.w 0x71d776 ; _dispatch_timers_run + 390
0x71d672: ldr.w r0, [r10, #8]
0x71d676: mvns r4, r0
0x71d678: ldr r0, [r4, #0x68]
0x71d67a: cmp r0, r6
0x71d67c: bne 0x71d65e ; _dispatch_timers_run + 110
0x71d67e: mov r8, r10
0x71d680: ldr r5, [r8, #24]!
0x71d684: ldr r2, [sp, #0x10]
0x71d686: ldr.w r11, [r8, #4]
0x71d68a: subs r0, r5, #0x1
0x71d68c: sbc r1, r11, #0x0
0x71d690: cmp r0, r2
0x71d692: mov.w r0, #0x0
0x71d696: it hs
0x71d698: movhs r0, #0x1
0x71d69a: ldr r2, [sp, #0xc]
0x71d69c: cmp r1, r2
0x71d69e: mov.w r1, #0x0
0x71d6a2: it hs
0x71d6a4: movhs r1, #0x1
0x71d6a6: it eq
0x71d6a8: moveq r1, r0
0x71d6aa: cmp r1, #0x0
0x71d6ac: bne 0x71d776 ; _dispatch_timers_run + 390
0x71d6ae: ldr r0, [r4, #0x1c]
0x71d6b0: cmp r0, #0x1
0x71d6b2: bhi 0x71d65e ; _dispatch_timers_run + 110
0x71d6b4: ldr r0, [r4, #0x70]
0x71d6b6: cmp r0, #0x0
0x71d6b8: bne 0x71d65e ; _dispatch_timers_run + 110
0x71d6ba: str r6, [sp, #0x4]
0x71d6bc: ldr.w r6, [r10, #48]
0x71d6c0: ldr.w r3, [r10, #52]
0x71d6c4: ldr r0, [sp, #0x10]
0x71d6c6: ldr r1, [sp, #0xc]
0x71d6c8: mov r2, r6
0x71d6ca: str r3, [sp, #0x8]
0x71d6cc: subs r0, r0, r5
0x71d6ce: sbc.w r1, r1, r11
0x71d6d2: blx 0x72b240 ; symbol stub for: __udivdi3
0x71d6d6: mov r9, r6
0x71d6d8: adds r6, r0, #0x1
0x71d6da: adc r12, r1, #0x0
0x71d6de: lsrs r1, r6, #0x1f
0x71d6e0: orr.w r1, r1, r12, lsl #1
0x71d6e4: movs r2, #0x0
0x71d6e6: mvn r3, #0x80000000
0x71d6ea: orr.w r1, r1, r12, lsr #31
0x71d6ee: cmp r1, #0x0
0x71d6f0: mov.w r1, #0x0
0x71d6f4: itt ne
0x71d6f6: movne.w r12, #0x0
0x71d6fa: mvnne r6, #0x80000000
0x71d6fe: cmp.w r9, #0xffffffff
0x71d702: it eq
0x71d704: moveq r1, #0x1
0x71d706: ldr r0, [sp, #0x8]
0x71d708: cmp r0, #0x0
0x71d70a: it lt
0x71d70c: movlt r2, #0x1
0x71d70e: cmp r0, r3
0x71d710: it eq
0x71d712: moveq r2, r1
0x71d714: mov r3, r0
0x71d716: cbnz r2, 0x71d73c ; _dispatch_timers_run + 332
0x71d718: umull r1, r2, r6, r9
0x71d71c: mla r2, r6, r3, r2
0x71d720: mla r0, r12, r9, r2
0x71d724: adds r2, r1, r5
0x71d726: adc.w r3, r0, r11
0x71d72a: strd r2, r3, [r8]
0x71d72e: ldrd r0, r1, [r10, #56]
0x71d732: adds r0, r0, r2
0x71d734: adcs r1, r3
0x71d736: strd r0, r1, [r10, #32]
0x71d73a: b 0x71d750 ; _dispatch_timers_run + 352
0x71d73c: mov.w r0, #0xffffffff
0x71d740: str.w r0, [r8]
0x71d744: str.w r0, [r8, #4]
0x71d748: str.w r0, [r8, #8]
0x71d74c: str.w r0, [r8, #12]
0x71d750: mov r0, r4
0x71d752: bl 0x71c5bc ; _dispatch_timers_update
0x71d756: ldr r0, [sp, #0x10]
0x71d758: ldr r1, [sp, #0xc]
0x71d75a: strd r0, r1, [r10, #40]
0x71d75e: ldrex r0, [r4, #0x70]
0x71d762: add r0, r6
0x71d764: strex r1, r0, [r4, #0x70]
0x71d768: cmp r1, #0x0
0x71d76a: bne 0x71d75e ; _dispatch_timers_run + 366
0x71d76c: mov r0, r4
0x71d76e: bl 0x715934 ; _dispatch_wakeup
0x71d772: ldr r6, [sp, #0x4]
0x71d774: b 0x71d664 ; _dispatch_timers_run + 116
0x71d776: adds r6, #0x1
0x71d778: cmp r6, #0x7
0x71d77a: bne.w 0x71d5fe ; _dispatch_timers_run + 14
0x71d77e: add sp, #0x18
0x71d780: pop.w {r8, r10, r11}
0x71d784: pop {r4, r5, r6, r7, pc}
0x71d786: nop
Can someone help me, please?
On iphone 4s it's ok (iOS 7)
Thank you in advance
Claudio
Related
I'm trying to change C quick sort code to ARM assembly code.
Firstly, I apologize for my long question.
just in case, I wrote whole codes.
but only part that makes problem is function recursion part.
I almost done this work except funcion recursion part.
I've also tried converting C codes to ARM assembly with gcc cross compiler to see how compiler do. But there are still few things that I can't understand well.
This is C code.
void quicksort_c(int array[8],int first,int last)
{
int i, j, pivot, temp;
if(first < last)
{
pivot = first;
i = first;
j = last;
while(i < j)
{
while(array[i] <= array[pivot] && i < last)
{
i++;
}
while(array[j] > array[pivot])
{
j--;
}
if(i < j)
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
temp = array[pivot];
array[pivot] = array[j];
array[j] = temp;
quicksort_c(array, first, j-1);
quicksort_c(array, j+1, last);
}
}
and this is arm assembly code that I wrote from scratch.
quicksort
STMFD sp!, {r0-r8,lr}
quicksort_recursion
CMP r1, r2 ;// if(first < last)
BGE out_of_if
outer_if
MOV r5, r1 ;// pivot = first
MOV r3, r1 ;// i = first;
MOV r4, r2 ;// j = last;
outer_while_loop
CMP r3, r4 ;// while(i < j)
BGE end_of_outer_while
outer_while
inner_while_1_loop
;//while(array[i] <= array[pivot] && i < last)
LDR r7, [r0, r3, lsl #2] ;//r7 = array[i]
LDR r8, [r0, r5, lsl #2] ;//r8 = array[pivot]
CMP r7, r8 ;//array[i] <= array[pivot]
BGT inner_while_2_loop
CMP r3, r2 ;// i < last
BGE inner_while_2_loop
inner_while_1
ADD r3, #1 ;//i++
B inner_while_1_loop
inner_while_2_loop
;//whlie(array[j] > array[pivot])
LDR r7, [r0, r4, lsl #2] ;// r7 = array[j]
LDR r8, [r0, r5, lsl #2] ;//r8 = array[pivot]
CMP r7, r8 ;// (array[j] > array[pivot])
BLE inner_if_cmp
inner_while_2
SUB r4, #1
B inner_while_2_loop
inner_if_cmp
CMP r3, r4;// if(i < j)
BGE outer_while_loop
inner_if
LDR r7, [r0, r3, lsl #2] ;// r7 = array[i]
MOV r6, r7 ;// temp = array[i]
LDR r8, [r0, r4, lsl #2] ;// r8 = array[j]
STR r8, [r0, r3, lsl #2] ;// array[i] = array[j]
STR r6, [r0, r4, lsl #2] ;// array[j] = temp;
B outer_while_loop
end_of_outer_while
LDR r7, [r0, r5, lsl #2] ;// r7 = array[pivot]
MOV r6, r7 ;// temp = array[pivot]
LDR r8, [r0, r4, lsl #2] ;// r8 = array[j]
STR r8, [r0, r5, lsl #2] ;// array[pivot] = array[j]
STR r6, [r0, r4, lsl #2] ;// array[j] = temp
;;//quicksort(array,first,j-1)
STMFD sp!, {r0-r8,lr}
SUBS r2, r4, #1
BL quicksort_recursion
;//LDMFD sp!, {r0-r8,pc}
;//quicksort(array, j+1, last)
STMFD sp!, {r0-r8,lr}
ADDS r1, r4, #1
BL quicksort_recursion
;//LDMFD sp!, {r0-r8,pc}
out_of_if
end_function
LDMFD sp!, {r0-r8,pc}
END
and this is how I use register
r0: array pointer
r1: first index
r2: last index
r3: i
r4: j
r5: pivot
r6: temp
r7: array[?] value
r8: array[?] value
I confirmed every parts except recursion of my code are work well.
At first, I did recursion in this way.
;;//quicksort(array,first,j-1)
SUBS r2, r4, #1
BL quicksort
;//quicksort(array, j+1, last)
ADDS r1, r4, #1
BL quicksort
but this code only do first function recursion.
ex)
Array before quicksorting : 5 1 4 7 8 3 6
Array after quicksorting : 1 2 4 3 5 8 7 6
I think it's because after function call, it doesn't go back to where it branched. so I added push and pop before and after function call like this.
;;//quicksort(array,first,j-1)
STMFD sp!, {r0-r8,lr}
SUBS r2, r4, #1
BL quicksort_recursion
;//quicksort(array, j+1, last)
STMFD sp!, {r0-r8,lr}
ADDS r1, r4, #1
BL quicksort_recursion
But this code falls in to infinite loop.
according to gcc compiled code,
quicksort_linux
cmp r1, r2
blt L16
bx lr
L16
push {r4, r5, r6, r7, r8, r9, r10, lr}
mov r10, r1
add ip, r0, r1, lsl #2
mov r5, r2
mov r4, r1
L3
lsls r3, r4, #2
add lr, r0, r3
ldr r7, [r0, r4, lsl #2]
ldr r6, [ip]
cmp r2, r4
ite le
movle r8, #0
movgt r8, #1
cmp r7, r6
it gt
movgt r8, #0
adds r3, r3, #4
add r3, r3, r0
cmp r8, #0
beq L9
L4
adds r4, r4, #1
mov lr, r3
ldr r7, [r3], #4
cmp r2, r4
ite le
movle r1, #0
movgt r1, #1
cmp r7, r6
it gt
movgt r1, #0
cmp r1, #0
bne L4
L9
lsls r3, r5, #2
add r9, r0, r3
ldr r1, [r0, r5, lsl #2]
cmp r1, r6
ble L5
subs r3, r3, #4
add r3, r3, r0
L6
subs r5, r5, #1
mov r9, r3
ldr r1, [r3], #-4
cmp r1, r6
bgt L6
L5
cmp r4, r5
bge L7
str r1, [lr]
str r7, [r9]
b L3
L7
mov r7, r2
mov r1, r10
mov r4, r0
ldr r3, [r0, r5, lsl #2]
str r3, [r0, r10, lsl #2]
str r6, [r0, r5, lsl #2]
subs r2, r5, #1
bl quicksort_linux
mov r2, r7
adds r1, r5, #1
mov r0, r4
bl quicksort_linux
pop {r4, r5, r6, r7, r8, r9, r10, pc}
END
It seems like they don't do any push or pop before or after branch but it works.
So, question is
1.what is problem of my function recursion code?
2.How can I fix that?
3.How can gcc compiled code works without any push and pop before and after function recursion?
I am running a project using the ARM Embedded Tollchain on a stm32 microcontroller which uses the newLib.
I called assert(false) to test the assert output and ended in a Hard Fault Exception. I debugged into the assembly of assert(...) and found out that a subsequent call to _exit(1) jumps to a Address which is called _etext. Taking a look to the manpage of _etext shows that _etext is the address of the end of the .text section.
I am really confused. Normally I had supposed that _exit() is calling __exit() (which is defined as global symbol by the newLib) which I had implemented in a file named syscalls.c.
Why does _exit() jump to _etext?
Here are some cope snippets for a better understanding:
The subsequent call to _exit() by assert() taken from newLib 2.5:
_VOID
_DEFUN_VOID (abort)
{
#ifdef ABORT_MESSAGE
write (2, "Abort called\n", sizeof ("Abort called\n")-1);
#endif
while (1)
{
raise (SIGABRT);
_exit (1);
}
}
The disassembly of abort and assert. Take a special look to address 0808a10a where the jump to 80a5198 (_etext) is performed:
abort:
0808a100: push {r3, lr}
0808a102: movs r0, #6
0808a104: bl 0x808bfdc <raise>
0808a108: movs r0, #1
0808a10a: bl 0x80a51d8
0808a10e: nop
__assert_func:
0808a110: push {lr}
0808a112: ldr r4, [pc, #40] ; (0x808a13c <__assert_func+44>)
0808a114: ldr r6, [r4, #0]
0808a116: mov r5, r0
0808a118: sub sp, #20
0808a11a: mov r4, r3
0808a11c: ldr r0, [r6, #12]
0808a11e: cbz r2, 0x808a136 <__assert_func+38>
0808a120: ldr r3, [pc, #28] ; (0x808a140 <__assert_func+48>)
0808a122: str r2, [sp, #8]
0808a124: stmia.w sp, {r1, r3}
0808a128: mov r2, r4
0808a12a: mov r3, r5
0808a12c: ldr r1, [pc, #20] ; (0x808a144 <__assert_func+52>)
0808a12e: bl 0x808a5f4 <fiprintf>
0808a132: bl 0x808a100 <abort>
0808a136: ldr r3, [pc, #16] ; (0x808a148 <__assert_func+56>)
0808a138: mov r2, r3
0808a13a: b.n 0x808a122 <__assert_func+18>
0808a13c: str r0, [r3, #120] ; 0x78
0808a13e: movs r0, #0
0808a140: add r12, r11
0808a142: lsrs r2, r1, #32
0808a144: add r12, sp
0808a146: lsrs r2, r1, #32
0808a148: add r8, sp
0808a14a: lsrs r2, r1, #32
The lss-file which shows that 80a5198 is the address of _etext:
0808a0c0 <abort>:
808a0c0: b508 push {r3, lr}
808a0c2: 2006 movs r0, #6
808a0c4: f001 ff6a bl 808bf9c <raise>
808a0c8: 2001 movs r0, #1
808a0ca: f01b f865 bl 80a5198 <_etext>
808a0ce: bf00 nop
I'm using floating point operations(software implementation) on a STM32F0 and found something weird in the listing. As soon as i use sqrtf, the linker is adding __aeabi_ddiv which is ~1.6kB of memory.
This code for example links to ddiv:
float value = 42.0f;
float root = sqrtf(value);
Removing sqrtf also removes ddiv. So my question:
Is this intended behavior?
If no, how can i fix it.
Is it possible to do sqrt without double?
Compiler: arm-atollic-eabi-gcc
Listing of sqrtf (ddiv at 0x800543e):
080053bc <sqrtf>:
80053bc: b5f0 push {r4, r5, r6, r7, lr}
80053be: 2500 movs r5, #0
80053c0: b08d sub sp, #52 ; 0x34
80053c2: 1c04 adds r4, r0, #0
80053c4: f000 f84a bl 800545c <__ieee754_sqrtf>
80053c8: 4b22 ldr r3, [pc, #136] ; (8005454 <sqrtf+0x98>)
80053ca: 1c06 adds r6, r0, #0
80053cc: 575d ldrsb r5, [r3, r5]
80053ce: 1c6b adds r3, r5, #1
80053d0: d030 beq.n 8005434 <sqrtf+0x78>
80053d2: 1c21 adds r1, r4, #0
80053d4: 1c20 adds r0, r4, #0
80053d6: f7fb febb bl 8001150 <__aeabi_fcmpun>
80053da: 1e07 subs r7, r0, #0
80053dc: d12a bne.n 8005434 <sqrtf+0x78>
80053de: 2100 movs r1, #0
80053e0: 1c20 adds r0, r4, #0
80053e2: f7fb f837 bl 8000454 <__aeabi_fcmplt>
80053e6: 2800 cmp r0, #0
80053e8: d024 beq.n 8005434 <sqrtf+0x78>
80053ea: 2301 movs r3, #1
80053ec: 9302 str r3, [sp, #8]
80053ee: 4b1a ldr r3, [pc, #104] ; (8005458 <sqrtf+0x9c>)
80053f0: 1c20 adds r0, r4, #0
80053f2: 9303 str r3, [sp, #12]
80053f4: 970a str r7, [sp, #40] ; 0x28
80053f6: f7fc faad bl 8001954 <__aeabi_f2d>
80053fa: 2200 movs r2, #0
80053fc: 9006 str r0, [sp, #24]
80053fe: 9107 str r1, [sp, #28]
8005400: 9004 str r0, [sp, #16]
8005402: 9105 str r1, [sp, #20]
8005404: 2300 movs r3, #0
8005406: 2d00 cmp r5, #0
8005408: d117 bne.n 800543a <sqrtf+0x7e>
800540a: 9208 str r2, [sp, #32]
800540c: 9309 str r3, [sp, #36] ; 0x24
800540e: a802 add r0, sp, #8
8005410: f000 f87a bl 8005508 <matherr>
8005414: 2800 cmp r0, #0
8005416: d018 beq.n 800544a <sqrtf+0x8e>
8005418: 9b0a ldr r3, [sp, #40] ; 0x28
800541a: 9301 str r3, [sp, #4]
800541c: 2b00 cmp r3, #0
800541e: d004 beq.n 800542a <sqrtf+0x6e>
8005420: f000 f874 bl 800550c <__errno>
8005424: 9b0a ldr r3, [sp, #40] ; 0x28
8005426: 9301 str r3, [sp, #4]
8005428: 6003 str r3, [r0, #0]
800542a: 9808 ldr r0, [sp, #32]
800542c: 9909 ldr r1, [sp, #36] ; 0x24
800542e: f7fc fae3 bl 80019f8 <__aeabi_d2f>
8005432: 1c06 adds r6, r0, #0
8005434: 1c30 adds r0, r6, #0
8005436: b00d add sp, #52 ; 0x34
8005438: bdf0 pop {r4, r5, r6, r7, pc}
800543a: 0010 movs r0, r2
800543c: 0019 movs r1, r3
800543e: f7fb ff55 bl 80012ec <__aeabi_ddiv>
8005442: 9008 str r0, [sp, #32]
8005444: 9109 str r1, [sp, #36] ; 0x24
8005446: 2d02 cmp r5, #2
8005448: d1e1 bne.n 800540e <sqrtf+0x52>
800544a: f000 f85f bl 800550c <__errno>
800544e: 2321 movs r3, #33 ; 0x21
8005450: 6003 str r3, [r0, #0]
8005452: e7e1 b.n 8005418 <sqrtf+0x5c>
8005454: 2000000c .word 0x2000000c
8005458: 08006096 .word 0x08006096
UPDATE I think I found the reason but still don't quite understand it.
Source of sqrtf
The double division is part of the exception handling, although 0.0/0.0 should be done at compile time right? If I call __ieee754_sqrtf directly ddiv is not linked. This solves my problem but I would like to know how to do this using sqrtf.
I am developping on an STM32F746 (ARM Cortex-M7) with the GNU ARM Toolchain (gcc 5.4.1) using FreeRTOS. I am using the following CFLAGS set:
-g -Werror -Wextra -O2 -fno-common -ffunction-sections -fmessage-length=0 -g -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-sp-d16 -fno-common -ffunction-sections -fmessage-length=0 -g -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-sp-d16
The following code shows '0' in the console as if the DMA controller was not powered on. Normally, writing RCC_AHB1ENR_DMA1EN in the AHB1ENR register power on the DMA controller.
/* *** Other peripheral configurations *** */
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
DMA1_Stream3->CR = DMA_SxCR_PL | DMA_SxCR_MINC |
DMA_SxCR_TCIE | DMA_SxCR_TEIE | DMA_SxCR_DMEIE;
DEBUG_PRINTF("%x\r\n", DMA1_Stream3->CR);
But the following code is printing the good value of DMA1_Stream3->CR.
/* *** Other peripheral configurations *** */
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
__asm__ __volatile__ ("" ::: "memory");
DMA1_Stream3->CR = DMA_SxCR_PL | DMA_SxCR_MINC |
DMA_SxCR_TCIE | DMA_SxCR_TEIE | DMA_SxCR_DMEIE;
DEBUG_PRINTF("%x\r\n", DMA1_Stream3->CR);
I never had to add those memory barriers for any other controllers so why do I have to do this for this one? I am thinking about either a load/store instructions reordering by GCC either a timing issue. I checked in errata sheet of the CPU (STM32F746) or datasheet but didn't find anything.
Here is the definition of the RCC structure:
typedef struct
{
/* ... */
__IO uint32_t AHB1ENR;
/* ... */
} RCC_TypeDef;
And here is the definition of the DMA1_Stream3 structure type:
typedef struct
{
__IO uint32_t CR; /*!< DMA stream x configuration register */
__IO uint32_t NDTR; /*!< DMA stream x number of data register */
__IO uint32_t PAR; /*!< DMA stream x peripheral address register */
__IO uint32_t M0AR; /*!< DMA stream x memory 0 address register */
__IO uint32_t M1AR; /*!< DMA stream x memory 1 address register */
__IO uint32_t FCR; /*!< DMA stream x FIFO control register */
} DMA_Stream_TypeDef;
__IO is defined as volatile.
Here is the assembly code generated for the function:
08003f4c <bsp_initSPIADIS>:
8003f4c: 4956 ldr r1, [pc, #344] ; (80040a8 <bsp_initSPIADIS+0x15c>)
8003f4e: 4a57 ldr r2, [pc, #348] ; (80040ac <bsp_initSPIADIS+0x160>)
8003f50: 6b08 ldr r0, [r1, #48] ; 0x30
8003f52: f440 7080 orr.w r0, r0, #256 ; 0x100
8003f56: b5f8 push {r3, r4, r5, r6, r7, lr}
8003f58: 6308 str r0, [r1, #48] ; 0x30
8003f5a: 2500 movs r5, #0
8003f5c: 6810 ldr r0, [r2, #0]
8003f5e: f240 3607 movw r6, #775 ; 0x307
8003f62: 4b53 ldr r3, [pc, #332] ; (80040b0 <bsp_initSPIADIS+0x164>)
8003f64: f44f 5eb8 mov.w lr, #5888 ; 0x1700
8003f68: f020 000c bic.w r0, r0, #12
8003f6c: 4c51 ldr r4, [pc, #324] ; (80040b4 <bsp_initSPIADIS+0x168>)
8003f6e: 4f52 ldr r7, [pc, #328] ; (80040b8 <bsp_initSPIADIS+0x16c>)
8003f70: 6010 str r0, [r2, #0]
8003f72: 6810 ldr r0, [r2, #0]
8003f74: f040 0008 orr.w r0, r0, #8
8003f78: 6010 str r0, [r2, #0]
8003f7a: 6890 ldr r0, [r2, #8]
8003f7c: f020 000c bic.w r0, r0, #12
8003f80: 6090 str r0, [r2, #8]
8003f82: 6890 ldr r0, [r2, #8]
8003f84: f040 0004 orr.w r0, r0, #4
8003f88: 6090 str r0, [r2, #8]
8003f8a: 6890 ldr r0, [r2, #8]
8003f8c: f040 0008 orr.w r0, r0, #8
8003f90: 6090 str r0, [r2, #8]
8003f92: 6a10 ldr r0, [r2, #32]
8003f94: f020 00f0 bic.w r0, r0, #240 ; 0xf0
8003f98: 6210 str r0, [r2, #32]
8003f9a: 6a10 ldr r0, [r2, #32]
8003f9c: f040 0010 orr.w r0, r0, #16
8003fa0: 6210 str r0, [r2, #32]
8003fa2: 6a10 ldr r0, [r2, #32]
8003fa4: f040 0040 orr.w r0, r0, #64 ; 0x40
8003fa8: 6210 str r0, [r2, #32]
8003faa: 6b08 ldr r0, [r1, #48] ; 0x30
8003fac: 4a43 ldr r2, [pc, #268] ; (80040bc <bsp_initSPIADIS+0x170>)
8003fae: f040 0002 orr.w r0, r0, #2
8003fb2: 6308 str r0, [r1, #48] ; 0x30
8003fb4: 6818 ldr r0, [r3, #0]
8003fb6: f020 5040 bic.w r0, r0, #805306368 ; 0x30000000
8003fba: 6018 str r0, [r3, #0]
8003fbc: 6818 ldr r0, [r3, #0]
8003fbe: f040 5000 orr.w r0, r0, #536870912 ; 0x20000000
8003fc2: 6018 str r0, [r3, #0]
8003fc4: 6898 ldr r0, [r3, #8]
8003fc6: f020 5040 bic.w r0, r0, #805306368 ; 0x30000000
8003fca: 6098 str r0, [r3, #8]
8003fcc: 6898 ldr r0, [r3, #8]
8003fce: f040 5080 orr.w r0, r0, #268435456 ; 0x10000000
8003fd2: 6098 str r0, [r3, #8]
8003fd4: 6898 ldr r0, [r3, #8]
8003fd6: f040 5000 orr.w r0, r0, #536870912 ; 0x20000000
8003fda: 6098 str r0, [r3, #8]
8003fdc: 6a58 ldr r0, [r3, #36] ; 0x24
8003fde: f020 6070 bic.w r0, r0, #251658240 ; 0xf000000
8003fe2: 6258 str r0, [r3, #36] ; 0x24
8003fe4: 6a58 ldr r0, [r3, #36] ; 0x24
8003fe6: f040 7080 orr.w r0, r0, #16777216 ; 0x1000000
8003fea: 6258 str r0, [r3, #36] ; 0x24
8003fec: 6a58 ldr r0, [r3, #36] ; 0x24
8003fee: f040 6080 orr.w r0, r0, #67108864 ; 0x4000000
8003ff2: 6258 str r0, [r3, #36] ; 0x24
8003ff4: 6b08 ldr r0, [r1, #48] ; 0x30
8003ff6: f040 0002 orr.w r0, r0, #2
8003ffa: 6308 str r0, [r1, #48] ; 0x30
8003ffc: 6818 ldr r0, [r3, #0]
8003ffe: f020 4040 bic.w r0, r0, #3221225472 ; 0xc0000000
8004002: 6018 str r0, [r3, #0]
8004004: 6818 ldr r0, [r3, #0]
8004006: f040 4000 orr.w r0, r0, #2147483648 ; 0x80000000
800400a: 6018 str r0, [r3, #0]
800400c: 6898 ldr r0, [r3, #8]
800400e: f020 4040 bic.w r0, r0, #3221225472 ; 0xc0000000
8004012: 6098 str r0, [r3, #8]
8004014: 6898 ldr r0, [r3, #8]
8004016: f040 4080 orr.w r0, r0, #1073741824 ; 0x40000000
800401a: 6098 str r0, [r3, #8]
800401c: 6898 ldr r0, [r3, #8]
800401e: f040 4000 orr.w r0, r0, #2147483648 ; 0x80000000
8004022: 6098 str r0, [r3, #8]
8004024: 6a58 ldr r0, [r3, #36] ; 0x24
8004026: f020 4070 bic.w r0, r0, #4026531840 ; 0xf0000000
800402a: 6258 str r0, [r3, #36] ; 0x24
800402c: 6a58 ldr r0, [r3, #36] ; 0x24
800402e: f040 5080 orr.w r0, r0, #268435456 ; 0x10000000
8004032: 6258 str r0, [r3, #36] ; 0x24
8004034: 6a58 ldr r0, [r3, #36] ; 0x24
8004036: f040 4080 orr.w r0, r0, #1073741824 ; 0x40000000
800403a: 6258 str r0, [r3, #36] ; 0x24
800403c: 6c0b ldr r3, [r1, #64] ; 0x40
800403e: 4820 ldr r0, [pc, #128] ; (80040c0 <bsp_initSPIADIS+0x174>)
8004040: f443 4380 orr.w r3, r3, #16384 ; 0x4000
8004044: 640b str r3, [r1, #64] ; 0x40
8004046: 61e5 str r5, [r4, #28]
8004048: 6026 str r6, [r4, #0]
800404a: 6823 ldr r3, [r4, #0]
800404c: 4e1d ldr r6, [pc, #116] ; (80040c4 <bsp_initSPIADIS+0x178>)
800404e: f023 0338 bic.w r3, r3, #56 ; 0x38
8004052: 6023 str r3, [r4, #0]
8004054: 6823 ldr r3, [r4, #0]
8004056: f043 0338 orr.w r3, r3, #56 ; 0x38
800405a: 6023 str r3, [r4, #0]
800405c: f8c4 e004 str.w lr, [r4, #4]
8004060: 6b0b ldr r3, [r1, #48] ; 0x30
8004062: 4c19 ldr r4, [pc, #100] ; (80040c8 <bsp_initSPIADIS+0x17c>)
8004064: f443 1300 orr.w r3, r3, #2097152 ; 0x200000
8004068: 630b str r3, [r1, #48] ; 0x30
800406a: 603a str r2, [r7, #0]
800406c: 6839 ldr r1, [r7, #0]
800406e: f000 faab bl 80045c8 <printf>
8004072: 4b16 ldr r3, [pc, #88] ; (80040cc <bsp_initSPIADIS+0x180>)
8004074: 4629 mov r1, r5
8004076: 2203 movs r2, #3
8004078: 601c str r4, [r3, #0]
800407a: 2001 movs r0, #1
800407c: f7fe f90e bl 800229c <xQueueGenericCreate>
8004080: 4629 mov r1, r5
8004082: 6170 str r0, [r6, #20]
8004084: 2203 movs r2, #3
8004086: 2001 movs r0, #1
8004088: f44f 4480 mov.w r4, #16384 ; 0x4000
800408c: f7fe f906 bl 800229c <xQueueGenericCreate>
8004090: 4b0f ldr r3, [pc, #60] ; (80040d0 <bsp_initSPIADIS+0x184>)
8004092: 2240 movs r2, #64 ; 0x40
8004094: f44f 4100 mov.w r1, #32768 ; 0x8000
8004098: 6130 str r0, [r6, #16]
800409a: 601c str r4, [r3, #0]
800409c: 6019 str r1, [r3, #0]
800409e: f883 230e strb.w r2, [r3, #782] ; 0x30e
80040a2: f883 230f strb.w r2, [r3, #783] ; 0x30f
80040a6: bdf8 pop {r3, r4, r5, r6, r7, pc}
80040a8: 40023800 andmi r3, r2, r0, lsl #16
80040ac: 40022000 andmi r2, r2, r0
80040b0: 40020400 andmi r0, r2, r0, lsl #8
80040b4: 40003800 andmi r3, r0, r0, lsl #16
80040b8: 40026058 andmi r6, r2, r8, asr r0
80040bc: 00030416 andeq r0, r3, r6, lsl r4
80040c0: 08008ec8 stmdaeq r0, {r3, r6, r7, r9, sl, fp, pc}
80040c4: 2000c2d0 ldrdcs ip, [r0], -r0
80040c8: 00030456 andeq r0, r3, r6, asr r4
80040cc: 40026070 andmi r6, r2, r0, ror r0
80040d0: e000e100 and lr, r0, r0, lsl #2
Yes after any operation enabling peripheral clock there is a bug in both STM32F4 & F7 micros. There is a small delay needed
I usually use __dsb(); for it. You can provide this delay (it is described in the errata but not for all affected uC (actually I have not found any unaffected F4 or F7)). I personally use dsb as it advised in the F4 errata, it reminds me about this bug.
2.1.5 Delay after an RCC peripheral clock enabling Description A delay between an RCC peripheral clock enable and the effective
peripheral enabling should be taken into account in order to manage
the peripheral read/write to registers. This delay depends on the
peripheral mapping: • If the peripheral is mapped on AHB: the delay
should be equal to 2 AHB cycles. • If the peripheral is mapped on APB:
the delay should be equal to 1 + (AHB/APB prescaler) cycles.
Workarounds
1. Use the DSB instructio n to stall the Cortex ®
-M4 CPU pipeline until the instruction is completed.
2. Insert “n” NOPs between the RCC enable bi t write and the peripheral register writes (n = 2 for AHB peripherals, n = 1 + AHB/
APB prescaler in case of APB peripherals).
3. Or simply insert a dummy read operation from the corresponding register just after enabling the peripheral clock.
I'm trying to understand why some Cortex-M0 code behaves differently when it is linked versus unlinked. In both cases it is loaded to 0x20000000. It looks like despite my best efforts to generate position independent code by passing -fPIC to the compiler, the bl instruction appears to differ after the code has passed through the linker. Am I reading this correctly, is that just a part of the linker's job in ARM Thumb, and is there a better way to generate a position independent function call?
Linked:
20000000:
20000000: 0003 movs r3, r0
20000002: 4852 ldr r0, [pc, #328]
20000004: 4685 mov sp, r0
20000006: 0018 movs r0, r3
20000008: f000 f802 bl 20000010
2000000c: 46c0 nop ; (mov r8, r8)
2000000e: 46c0 nop ; (mov r8, r8)
Unlinked:
00000000:
0: 0003 movs r3, r0
2: 4852 ldr r0, [pc, #328]
4: 4685 mov sp, r0
6: 0018 movs r0, r3
8: f7ff fffe bl 10
c: 46c0 nop ; (mov r8, r8)
e: 46c0 nop ; (mov r8, r8)
start.s
.globl _start
_start:
.word 0x20001000
.word reset
.word hang
.word hang
.thumb
.thumb_func
reset:
bl notmain
.thumb_func
hang:
b .
notmain.c
unsigned int x;
unsigned int fun ( unsigned int );
void notmain ( void )
{
x=fun(x+5);
}
fun.c
unsigned int y;
unsigned int fun ( unsigned int z )
{
return(y+z+1);
}
memmap
MEMORY
{
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > ram
.bss : { *(.bss*) } > ram
}
build
arm-none-eabi-as start.s -o start.o
arm-none-eabi-gcc -fPIC -O2 -c -mthumb fun.c -o fun.o
arm-none-eabi-gcc -fPIC -O2 -c -mthumb notmain.c -o notmain.o
arm-none-eabi-ld -T memmap start.o notmain.o fun.o -o so.elf
produces
20000000 <_start>:
20000000: 20001000 andcs r1, r0, r0
20000004: 20000011 andcs r0, r0, r1, lsl r0
20000008: 20000015 andcs r0, r0, r5, lsl r0
2000000c: 20000015 andcs r0, r0, r5, lsl r0
20000010 <reset>:
20000010: f000 f802 bl 20000018 <notmain>
20000014 <hang>:
20000014: e7fe b.n 20000014 <hang>
...
20000018 <notmain>:
20000018: b510 push {r4, lr}
2000001a: 4b06 ldr r3, [pc, #24] ; (20000034 <notmain+0x1c>)
2000001c: 4a06 ldr r2, [pc, #24] ; (20000038 <notmain+0x20>)
2000001e: 447b add r3, pc
20000020: 589c ldr r4, [r3, r2]
20000022: 6823 ldr r3, [r4, #0]
20000024: 1d58 adds r0, r3, #5
20000026: f000 f809 bl 2000003c <fun>
2000002a: 6020 str r0, [r4, #0]
2000002c: bc10 pop {r4}
2000002e: bc01 pop {r0}
20000030: 4700 bx r0
20000032: 46c0 nop ; (mov r8, r8)
20000034: 00000032 andeq r0, r0, r2, lsr r0
20000038: 00000000 andeq r0, r0, r0
2000003c <fun>:
2000003c: 4b03 ldr r3, [pc, #12] ; (2000004c <fun+0x10>)
2000003e: 4a04 ldr r2, [pc, #16] ; (20000050 <fun+0x14>)
20000040: 447b add r3, pc
20000042: 589b ldr r3, [r3, r2]
20000044: 681b ldr r3, [r3, #0]
20000046: 3301 adds r3, #1
20000048: 1818 adds r0, r3, r0
2000004a: 4770 bx lr
2000004c: 00000010 andeq r0, r0, r0, lsl r0
20000050: 00000004 andeq r0, r0, r4
Disassembly of section .got:
20000054 <.got>:
20000054: 20000068 andcs r0, r0, r8, rrx
20000058: 2000006c andcs r0, r0, ip, rrx
Disassembly of section .got.plt:
2000005c <_GLOBAL_OFFSET_TABLE_>:
...
Disassembly of section .bss:
20000068 <x>:
20000068: 00000000 andeq r0, r0, r0
2000006c <y>:
2000006c: 00000000 andeq r0, r0, r0
when it wants to find the global variable x what it appears to have done is it takes the program counter and a linker supplied/modfied offset 0x32 and uses that to find the entry in the global offset table. then takes an offset from that to find X. same for Y. so it appears that when you relocate you will need to modify the global offset table at runtime or load time depending.
If I get rid of those global variables, other than the vector table which is hardcoded and not PIC (and wasnt compiled anyway), this is all position independent.
20000000 <_start>:
20000000: 20001000 andcs r1, r0, r0
20000004: 20000011 andcs r0, r0, r1, lsl r0
20000008: 20000015 andcs r0, r0, r5, lsl r0
2000000c: 20000015 andcs r0, r0, r5, lsl r0
20000010 <reset>:
20000010: f000 f802 bl 20000018 <notmain>
20000014 <hang>:
20000014: e7fe b.n 20000014 <hang>
...
20000018 <notmain>:
20000018: b508 push {r3, lr}
2000001a: 2005 movs r0, #5
2000001c: f000 f804 bl 20000028 <fun>
20000020: 3006 adds r0, #6
20000022: bc08 pop {r3}
20000024: bc02 pop {r1}
20000026: 4708 bx r1
20000028 <fun>:
20000028: 3001 adds r0, #1
2000002a: 4770 bx lr
back to this version
unsigned int y;
unsigned int fun ( unsigned int z )
{
return(y+z+1);
}
position independent
00000000 <fun>:
0: 4b03 ldr r3, [pc, #12] ; (10 <fun+0x10>)
2: 4a04 ldr r2, [pc, #16] ; (14 <fun+0x14>)
4: 447b add r3, pc
6: 589b ldr r3, [r3, r2]
8: 681b ldr r3, [r3, #0]
a: 3301 adds r3, #1
c: 1818 adds r0, r3, r0
e: 4770 bx lr
10: 00000008 andeq r0, r0, r8
14: 00000000 andeq r0, r0, r0
not position independent
00000000 <fun>:
0: 4b02 ldr r3, [pc, #8] ; (c <fun+0xc>)
2: 681b ldr r3, [r3, #0]
4: 3301 adds r3, #1
6: 1818 adds r0, r3, r0
8: 4770 bx lr
a: 46c0 nop ; (mov r8, r8)
c: 00000000 andeq r0, r0, r0
the code has to do a bit more work to access the external variable. position dependent, some work because it is external but not as much. the linker will fill in the required items to make it work...to link it...
the elf file contains information for the linker to know to do this.
Relocation section '.rel.text' at offset 0x1a4 contains 2 entries:
Offset Info Type Sym.Value Sym. Name
00000010 00000a19 R_ARM_BASE_PREL 00000000 _GLOBAL_OFFSET_TABLE_
00000014 00000b1a R_ARM_GOT_BREL 00000004 y
or
Relocation section '.rel.text' at offset 0x174 contains 1 entries:
Offset Info Type Sym.Value Sym. Name
0000000c 00000a02 R_ARM_ABS32 00000004 y
notmain had these PIC
Relocation section '.rel.text' at offset 0x1cc contains 3 entries:
Offset Info Type Sym.Value Sym. Name
0000000e 00000a0a R_ARM_THM_CALL 00000000 fun
0000001c 00000b19 R_ARM_BASE_PREL 00000000 _GLOBAL_OFFSET_TABLE_
00000020 00000c1a R_ARM_GOT_BREL 00000004 x
and without.
Relocation section '.rel.text' at offset 0x198 contains 2 entries:
Offset Info Type Sym.Value Sym. Name
00000008 00000a0a R_ARM_THM_CALL 00000000 fun
00000014 00000b02 R_ARM_ABS32 00000004 x
so in short the toolchain is doing its job, you dont need to re-do its job. And note this has nothing to do with arm or thumb. any time you use the object and linker model and allow for external items from an object the linker has to patch things up to glue the code together. thats just how it works.