Throwing data abort exception - linux

I was debugging the following code on CPULator
.global _start
_start:
MOV R4, #0x61
LDR R0, =freq
ADD R0, R4
LDR R2, [R0]
ADD R2, #1
STR R2, [R0]
_exit:
MOV R7, #1
SWI 0
.data
freq: .rept 128
.word 0x00 # initialise character counts as 0
.endr
I get an error on the CPULator console:
0000000c Warning: Memory read of 4 bytes at address 00000089 is misaligned. Throwing data abort exception.
Simulator requested a breakpoint.
The exception was thrown on line 7:
LDR R2, [R0]
Why is this and how can I solve it?

the CPU is trying to access an odd address of the memory.
LDR R2, [R0] --> Load R2 with the content of the memory address referenced by R0
R0 contains and odd number.
All 32-bit and 64-bit CPU's can access even addresses of the memory:
0x00000000 is good
0x00000004 is good
0x00000008 is good
0x00000009 is not good
Enrico Migliore
P.S.
CPU's can only access: "aligned memory addresses" which are even addresses multiple of 4 or 8 depending on the CPU type.
A very few and special ARM instructions can access "unaligned addresses".
Take a look at here:
https://community.arm.com/developer/tools-software/oss-platforms/f/dev-platforms-forum/8806/loads-and-stores-for-unaligned-memory-addresses

Related

Armv7 Assembly - Extra console prompt "pi#raspberrypi:~ $ " when I press enter?

I get this output from my program which takes a user input, and replaces the linefeed with a null terminating and prints it back out to the console
pi#raspberrypi:~ $ ./tester
Please enter 4 different numbers between 1-5 together without space or special characters.
1234
1234
pi#raspberrypi:~ $
pi#raspberrypi:~ $
But when I type 123 I only get a single line prompt which is what I'm looking for when I enter 1234.
pi#raspberrypi:~ $ ./tester
Please enter 4 different numbers between 1-5 together without space or special characters.
123
123
pi#raspberrypi:~ $
This is the code I'm executing, it's as minimum as I could get it for minimum functional requirements.
.global _start
_start:
LDR r1, =prompt
BL _sPrint
LDR r1, =userInput # point to the space allocated for input
MOV r2, #4 # set the limit of character to read in
BL _sInput
LDR r1, =userInput
BL _sPrint
Ldr r1, =newline
BL _sPrint
B _exit
#_sPrint prints out a string based on it's variable length determined by _strlen
#strlen, and findEnd are both needed for _sPrint.
_sPrint:
MOV r7, #4 #sets r7 to console STDOUT
MOV r0, #1 #set WRITE destination to STDOUT (terminal)
PUSH {r0, r1, lr}
BL _strLen #gets the stringlength and the end
POP {r0, r1, lr}
SWI 0
mov pc, lr
_strLen:
mov r2, #0
#find end of strlen finds the end of the string and stores the length in r2 for console output
findEnd:
LDRB r0, [r1], #1
ADD r2, r2, #1
CMP r0, #0
BNE findEnd
SUB r2, r2, #1
MOV pc, lr
_sInput:
PUSH {R1-R8, lr}
MOV r7, #3 #register r7 being set to 3 to indicate message being read in (read syscall)
MOV r0, #0 #Set READ device to the STDIN (keyboard)
SWI 0
POP {R1-R8, lr}
#String fix takes a string value at r1's address and changes the line feed to be null termianted.
strfx:
LDRB r0, [r1],#1 #loads a single byte from r1 (r1 is dereferenced), which is the _sInput to r0
CMP r0, #10 #is r0 our newline?
BNE strfx
MOV r0, #0 #set r0 to null
STRB r0, [r1, #-1] #store r0's value back into r1's current address location. The final address
MOV PC, LR #location of r1 newline to be the NULL in r1.
_exit:
MOV r7, #1
SWI #0
.data
prompt: .asciz "\nPlease enter 4 different numbers between 1-5 together without space or special characters. \n \n"
newline: .asciz "\n"
userInput: .space 6
You're reading four characters. When the user enters "1234\n" (five characters), the newline is left in the input buffer to be read by the shell. When the user enters "123\n", the newline is actually read by you. Since you have newline-handling code, the solution is simple: you need to read five characters, not four.

Why the arm port of Linux kernel did not backup the "cpsr" register during the context switch?

The switch to assembly of arm32 in linux is like that:
you coud see there are no cpsr reigister backup, compare to others arch, like mips or riscv,
which corresponding mstatus and status register are all do the backup and restore during the _switch_to, so, why there are the differences?
12948 8010d328 <__switch_to>:
12949 8010d328: e281c018 add ip, r1, #24
12950 8010d32c: e8ac6ff0 stmia ip!, {r4, r5, r6, r7, r8, r9, sl, fp, sp, lr}
12951 8010d330: e592405c ldr r4, [r2, #92] ; 0x5c
12952 8010d334: e5925060 ldr r5, [r2, #96] ; 0x60
12953 8010d338: ee1d7f50 mrc 15, 0, r7, cr13, cr0, {2}
12954 8010d33c: ee0d4f70 mcr 15, 0, r4, cr13, cr0, {3}
12955 8010d340: ee0d5f50 mcr 15, 0, r5, cr13, cr0, {2}
12956 8010d344: e5817060 str r7, [r1, #96] ; 0x60
12957 8010d348: e1a05000 mov r5, r0
12958 8010d34c: e2824018 add r4, r2, #24
12959 8010d350: e59f000c ldr r0, [pc, #12] ; 8010d364 <__switch_to+0x3c>
12960 8010d354: e3a01002 mov r1, #2
12961 8010d358: eb00c813 bl 8013f3ac <atomic_notifier_call_chain>
12962 8010d35c: e1a00005 mov r0, r5
12963 8010d360: e894aff0 ldm r4, {r4, r5, r6, r7, r8, r9, sl, fp, sp, pc}
12964 8010d364: 80b61200 .word 0x80b61200
12965 8010d368: e58d403c str r4, [sp, #60] ; 0x3c
12966 8010d36c: e1a0f009 mov pc, r9
There are a few different uses of cpsr and it is not clear which one you are referring to.
The supervisor mode cpsr.
The user mode cpsr.
Some exception cpsr.
These values are stored during an exception on an ARM cpu.
See: Linux kernel ARM exception stack
This makes all 'spsr' except the svc and user mode meaningless.
Note: The ARM has banked SP, cpsr and lr. Other referenced architectures may or may not have banked registers. For certain, all need to restore the user mode status register or user CPSR on ARM.
The switch_to assembler is used to switch kernel state for a process. The sp that is restored is an 8k page where the lower portion is a thread_info holding a copy of the user registers. The switch_to() function takes a from and to thread_info held in R1 and R2.
The code,
add r4, r2, #24
ldm r4, {r4, r5, r6, r7, r8, r9, sl, fp, sp, pc}
Is more like a longjmp() to a previous call to switch_to(); the code is not heading to the same place it was called from necessarily. The SPSR which is the return to user mode CPSR (and lr). These are saved in r1,r2 by the vector stubs. They are restored by the restore_user_regs macro. The instruction movs pc, lr will restore the user CPSR and return from an exception/syscall.
The cpsr (SVC) active with kernel code is protected by the 'C' ABI which says the status bits are not valid after a function call. It is also assumed the any svc code uses the same 'T' bit (all kernel code is either Thumb or ARM only) and the function needs to be called with 'F' and 'I' bits in a known state. switch_to callers should use the stacking mask functions OR never have interrupts masked. I think it is probably the last one. If you try to mix Thumb/ARM code or use/change interrupt masking with calls to switch_to, it would be an issue; otherwise, there is no need to save/restore this value.

Program crashes on STRB instruction on ARMv6

While learning ARMv6 ASM (using raspberry pi) I was trying to implement a loop which would modify the contents of a string, however I cannot seem to store the modified byte back to memory.
Using GDB and breaking at various points shows me all registry values are working perfectly until it comes to the STRB instruction. Then it crashes for some unknown reason.
The loop should decrement all bytes by 1 in reverse order.
.text
.global _start
_start:
/* Thumb mode */
.code 32
add r6, pc, #1
bx r6
.code 16
mov r4, #6
mov r0, pc
add r0, #16
loop:
/*load, modify, store*/
ldrb r3, [r0]
sub r3, #1
strb r3, [r0] /*THIS IS BROKEN*/
sub r0, #1
sub r4, r4, #1
bne loop
bx lr
.data
string:
asciz "HiThere"
The STRB instruction seems to crash the program, I am using an old book to learn from, am I missing something obvious here?
EDIT: yes I know that isnt the best way to load r0 but it works...i guess it could use a label in future.
EDIT2: Sorry I know my question was badly written, Ive included more code for clarity. Still crashes on STRB when stepping through in gdb.
EDIT: rather than increasing r0, your loop decreases it. So, rather than scrolling through the string, you are scrolling up straight into your code, overwriting instructions with less-by-one byte values. Once you overwrite the strb instruction, SIGILL happens.
Replace
sub r0, #1
with
add r0, #1
PREVIOUS: I see r0 being initialized to a memory location in the code section, past pc. Is that a writable memory block? I'm not so sure.
Place the string in the data section instead.
EDIT: there's another thing; your loop has no exit condition. SUB doesn't set flags unless told to; so replace
sub r4, r4, #1
with
subs r4, r4, #1

How to print a number in ARM assembly?

I am trying to print a number that I have stored. I'm not sure if I am close or way off. Any help would be appreciated though. Here is my code:
.data
.balign 4
a: .word 4
.text
.global main
main:
ldr r0, addr_of_a
mov r1, #8
str r1, [r0]
write:
mov r0, #1
ldr r1, addr_of_a
mov r2, #4
mov r7, #4
swi #0
bx lr
addr_of_a: .word a
It compiles and runs, but I don't see anything printed. From what I understand, I need the address of where to start printing in r1, how many bytes in r2, the file descriptor in r0, and r7 specifies the write call if it is set to #4. I am simply trying to store #8, then print the stored number.
The syscall write takes on the second argument (r1) as a pointer to the string you want to print. You are passing it a pointer to an integer, which is why it's not printing anything, because there are no ASCII characters on the memory region you are passing to it.
Below you'll find a "Hello World" program using the syscall write.
.text
.global main
main:
push {r7, lr}
mov r0, #1
ldr r1, =string
mov r2, #12
mov r7, #4
svc #0
pop {r7, pc}
.data
string: .asciz "Hello World\n"
If you want to print a number you can use the printf function from the C library. Like this:
.text
.global main
.extern printf
main:
push {ip, lr}
ldr r0, =string
mov r1, #1024
bl printf
pop {ip, pc}
.data
string: .asciz "The number is: %d\n"
Finally, if you want to print the number with the syscall write you can also implement a itoa function (one that converts an integer to a string).
Hi I appreciate that this is a pretty old thread but I've scratched my head over this for a while and would like to share my solution. Maybe it'll help someone along the way!
I was aiming to print to digit without recourse to using C++ in any way, though I realise that simply decompiling a tostring() - or whatever equivalent exists in C++ - and seeing what that came up with would have been a far quicker route.
Basically I ended up with creating a pointer to an empty .ascii string in the section .data and added the digit that I wanted to print + 48 to it before printing off that digit.
The +48 of course is to refer to the specific digit's ascii index number.
.global _start
_start:
MOV R8, #8
ADD R8, R8, #48
LDR R9, =num
STR R8, [R9]
MOV R0, #1
LDR R1, =num
MOV R2, #1
MOV R7, #4
SWI 0
.data
num:
.ascii: " "
The biggest drawback of this approach is that it doesn't handle any number more than one digit long of course.
My solution for that was much, much uglier and beyond the scope of this answer here but if you've a strong stomach you can see it here:

How to print out registers in Linux kernel?

I want to print out values of a couple of registers from the linux kernel code running on ARM. Particularly I have the following assembly in linux -
e3c52007 bic r2, r5, #7 ; 0x7
e1520003 cmp r2, r3
0a000003 beq c011fa60 <smem_find+0x40>
How do I print out the values of r2, r3 and r5 in kmsg? I do not want to use the variable names and want to get the values from registers.
I'm not that familiar with kernel development and easy ways to debug, but this would do the job I guess.
size_t r2, r3, r5;
asm ("str r2, %[r2]\n"
"str r3, %[r3]\n"
"str r5, %[r5]\n"
: [r2]"=m" (r2), [r3]"=m" (r3), [r5]"=m" (r5));
printk("r2=%u r3=%u r4=%u\n", r2, r3, r5);
Edit: Now with ARM assembly instead of x86 :p
You can call show_regs(struct pt_regs * regs). This function will diplay all the registrs on the pt_regs structure.

Resources