1 .data
2
3 .balign 4
4 message1: .asciz "Enter name: "
5
6 .balign 4
7 message2: .asciz "name is %s\n"
8
9 .balign 4
10 scan_pattern: .asciz "%s"
11
12 .balign 4
13 string_read: .space 100
14
15 .balign 4
16 return: .word 0
17
18 .text
19
20 .global main
21 main:
22 ldr r1, address_return //load return address in r1
23 str lr, [r1] //store value of lr in r1
24
25 ldr r0, address_message1 //load message1 address in r0
26 bl printf //call printf on r0
27
28 ldr r0, address_scan_pattern //load scanpattern address in r0
29 ldr r1, address_string_read //load number_read address in r1
30 bl scanf //call scanf
31
32 ldr r0, address_message2 //load message2 address in r0
33 ldr r1, address_string_read //load address_number_read in r1
34 ldr r1, [r1] //load value of r1 into r1
35 bl printf //call printf
36
37 ldr r0, address_string_read //load address_number_read in r0
38 ldr r0, [r0] //value of r0 in r0
39
40 ldr lr, address_return //load address of return in lr
41 ldr lr, [lr] //load value of lr in lr
42 bx lr //go to lr
43
44 address_message1: .word message1
45 address_message2: .word message2
46 address_scan_pattern: .word scan_pattern
47 address_string_read: .word string_read
48 address_return: .word return
49
50 .global printf
51 .global scanf
It seems to read the name, but when I try to print it, it give me a segmentation fault. I don't know where it went wrong. Any hint or help is appreciated. I did allocate space to hold the string so where is the segv coming from?
Okay, I think I see the problem. BTW, thanks for the excellent commenting--sidebar on every line. Keep it up. It's what asm experts do. There's no such thing as too many comments for assembler.
I presume that the printf on line 26 worked. It was the printf on line 35 that failed.
The first printf only needs one pointer argument [in r0]. Notice exactly how you loaded r0.
The second printf needs two pointer arguments. First arg into r0, using the same method as the first printf.
Look at how you loaded r1 for the second argument. It should be similar to what you did for r0.
But ... It's not. For r1, you've got an extra indirect load on line 34. I think if you remove it, things will work.
It's the equivalent of:
char *str = "Hello World";
printf("My str: %s\n",*str); // what you did
printf("My str: %s\n",str); // what you intended
Related
I'm starter using Arm assembly, I occur the segmentaion fault at line str. I think, Register has address memory about var3 and Store value to memory var3 using register 11.
I don't think there is any problem with my code..
Please solve my error code.
exam.s
.text
.global main
main:
adr r3, var1
ldr r0, [r3]
mov r0,r0, LSL #2
adr r3, var2
ldr r1, [r3]
and r1,r1,#15
orr r1,r0,r1
adr r11,var3
str r1,[r11],#4
mov r0,#0
mov r7,#1
swi 0
var1: .word 10
var2: .word 20
var3: .word 0
Your variables are in the .text section, which is non-writable in sane systems (for security and efficiency reasons).
Put a .data section declaration before the variable declarations.
According to this thread, initializing an array with a shorter string literal pads the array with zeros.
So, is there any reason why these two functions (test1 and test2) would produce different results when compiled for ARM Cortex M4?
extern void write(char * buff);
void test1(void)
{
char buff[8] = {'t', 'e', 's', 't', 0, 0, 0, 0 };
write(buff);
}
void test2(void)
{
char buff[8] = "test";
write(buff);
}
I am getting equivalent assemblies for x86-64, but on ARM gcc I get different output:
test1:
str lr, [sp, #-4]!
sub sp, sp, #12
mov r3, sp
ldr r2, .L4
ldm r2, {r0, r1}
stm r3, {r0, r1}
mov r0, r3
bl write
add sp, sp, #12
ldr pc, [sp], #4
.L4:
.word .LANCHOR0
test2:
mov r3, #0
str lr, [sp, #-4]!
ldr r2, .L8
sub sp, sp, #12
ldm r2, {r0, r1}
str r0, [sp]
mov r0, sp
strb r1, [sp, #4]
strb r3, [sp, #5]
strb r3, [sp, #6]
strb r3, [sp, #7]
bl write
add sp, sp, #12
ldr pc, [sp], #4
.L8:
.word .LANCHOR0+8
First of, the code is equivalent in the sense that the contents of memory constituting the objects named buf will be the same.
That said, the compiler clearly produces worse code for the second function. Consequently, since there is a way to produce more optimized code that has equivalent semantics, it would be reasonable to consider this an optimization failure in the compiler and file a bug for it.
If the compiler wanted to emit the same code, it would have to recognize that the string literal representation in memory can be zero-padded without changing the semantics of the program (though the string literal itself cannot be padded, since sizeof "test" cannot be equal to sizeof "test\0\0\0").
However, since this would only be advantageous if the string literal is used to initialize an explicit-length array (usually a bad idea) that is longer than the literal and where normal string semantics are not sufficient (bytes past the null-terminator are relevant), the value of better optimization for this case seems limited.
Addendum: If you set godbolt to not remove assembler directives, you can see how the literals are created:
.section .rodata
.align 2
.set .LANCHOR0,. + 0
.byte 116
.byte 101
.byte 115
.byte 116
.byte 0
.byte 0
.byte 0
.byte 0
.ascii "test\000"
.space 3
Interestingly, the compiler does not deduplicate, and it leaves the padding after the string literal to the assembler (.space 3), rather than explicitly zeroing it.
I am trying to figure out how arrays work in ARM assembly, but I am just overwhelmed. I want to initialize an array of size 20 to 0, 1, 2 and so on.
A[0] = 0
A[1] = 1
I can't even figure out how to print what I have to see if I did it correctly. This is what I have so far:
.data
.balign 4 # Memory location divisible by 4
string: .asciz "a[%d] = %d\n"
a: .skip 80 # allocates 20
.text
.global main
.extern printf
main:
push {ip, lr} # return address + dummy register
ldr r1, =a # set r1 to index point of array
mov r2, #0 # index r2 = 0
loop:
cmp r2, #20 # 20 elements?
beq end # Leave loop if 20 elements
add r3, r1, r2, LSL #2 # r3 = r1 + (r2*4)
str r2, [r3] # r3 = r2
add r2, r2, #1 # r2 = r2 + 1
b loop # branch to next loop iteration
print:
push {lr} # store return address
ldr r0, =string # format
bl printf # c printf
pop {pc} # return address
ARM confuses me enough as it is, I don't know what i'm doing wrong. If anyone could help me better understand how this works that would be much appreciated.
This might help down the line for others who want to know about how to allocate memory for array in arm assembly language
here is a simple example to add corresponding array elements and store in the third array.
.global _start
_start:
MOV R0, #5
LDR R1,=first_array # loading the address of first_array[0]
LDR R2,=second_array # loading the address of second_array[0]
LDR R7,=final_array # loading the address of final_array[0]
MOV R3,#5 # len of array
MOV R4,#0 # to store sum
check:
cmp R3,#1 # like condition in for loop for i>1
BNE loop # if R3 is not equal to 1 jump to the loop label
B _exit # else exit
loop:
LDR R5,[R1],#4 # loading the values and storing in registers and base register gets updated automatically R1 = R1 + 4
LDR R6,[R2],#4 # similarly
add R4,R5,R6
STR R4,[R7],#4 # storing the values back to the final array
SUB R3,R3,#1 # decrment value just like i-- in for loop
B check
_exit:
LDR R7,=final_array # before exiting checking the values stored
LDR R1, [R7] # R1 = 60
LDR R2, [R7,#4] # R2 = 80
LDR R3, [R7,#8] # R3 = 100
LDR R4, [R7,#12] # R4 = 120
MOV R7, #1 # terminate syscall, 1
SWI 0 # execute syscall
.data
first_array: .word 10,20,30,40
second_array: .word 50,60,70,80
final_array: .word 0,0,0,0,0
as mentioned your printf has problems, you can use the toolchain itself to see what the calling convention is, and then conform to that.
#include <stdio.h>
unsigned int a,b;
void notmain ( void )
{
printf("a[%d] = %d\n",a,b);
}
giving
00001008 <notmain>:
1008: e59f2010 ldr r2, [pc, #16] ; 1020 <notmain+0x18>
100c: e59f3010 ldr r3, [pc, #16] ; 1024 <notmain+0x1c>
1010: e5921000 ldr r1, [r2]
1014: e59f000c ldr r0, [pc, #12] ; 1028 <notmain+0x20>
1018: e5932000 ldr r2, [r3]
101c: eafffff8 b 1004 <printf>
1020: 0000903c andeq r9, r0, ip, lsr r0
1024: 00009038 andeq r9, r0, r8, lsr r0
1028: 0000102c andeq r1, r0, ip, lsr #32
Disassembly of section .rodata:
0000102c <.rodata>:
102c: 64255b61 strtvs r5, [r5], #-2913 ; 0xb61
1030: 203d205d eorscs r2, sp, sp, asr r0
1034: 000a6425 andeq r6, sl, r5, lsr #8
Disassembly of section .bss:
00009038 <b>:
9038: 00000000 andeq r0, r0, r0
0000903c <a>:
903c:
the calling convention is generally first parameter in r0, second in r1, third in r2 up to r3 then use the stack. There are many exceptions to this, but we can see here that the compiler which normally works fine with a printf call, wants the address of the format string in r0. the value of a then the value of b in r1 and r2 respectively.
Your printf has the string in r0, but a printf call with that format string needs three parameters.
The code above used a tail optimization and branch to printf rather than called it and returned from. The arm convention these days prefers the stack to be aligned on 64 bit boundaries, so you can put some register, you dont necessarily care to preserve on the push/pop in order to keep that alignment
push {r3,lr}
...
pop {r3,pc}
It certainly wont hurt you to do this, it may or may not hurt to not do it depending on what downstream assumes.
Your setup and loop should function just fine assuming that r1 (label a) is a word aligned address. Which it may or may not be if you mess with your string, should put a first then the string or put another alignment statement before a to insure the array is aligned. There are instruction set features that can simply the code, but it appears functional as is.
(The problem is based on assembly language ARM.)
I'm dealing with a problem which asking me to reverse a given array.
Just like this:
Given array: 1, 2, 3, 4, 5
Reversed array: 5, 4, 3, 2, 1
And the limitation of this problem is that I'm only supposed to use registers r0-r3.
I have a basic algorithm, but I'm really confused when I'm trying to implement the idea.
My algorithm:
Loop:
1. get value from head pointer, ptr++
2. get value from tail pointer, ptr--
3. swap them
4. check if head pointer and tail pointer cross,
if so, exit loop and return.
if not, go back to loop.
But I just don't know how to use only 4 registers to solve this problem..
Below would be all I have currently.
.text
.global reverse
reverse:
# See if head and tail ptr cross
# If so, end loop (b end)
head:
# use r2 to represent head value
ldr r2,[r0] # r2 <-*data get the first value
tail:
# mov r1,r1 # size
sub r1,r1,#1 # size-1
lsl r1,r1,#2 # (size-1)*4
add r0,r0,r1 # &data[size-1] need to ldr r1,[r0] to get value
ldr r1,[r0] # get value for r1 (from tail)
swap:
# swap values
mov r3, r1 #store value to r3
str r2, [r0]
# head ptr ++
# tail ptr --
# back to reverse
end:
# loop ends
Crude and inefficient example
.data
Array: .word 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,32,64,128,256,512
.equ len.Array,.-Array
.text
.global main
main:
nop
sub sp, sp, #len.Array // save space on stack
ldr r1,=Array // Array
mov r2, #len.Array // length of array
mov r3, #0 // zero init counter Array
1:
ldr r0, [r1,r3] // load word size element position x from Array
push {r0} // push element value into stack
add r3, r3, #4 // inc Array counter by 4 since word size is 4 bytes
cmp r3, r2 //
blt 1b
// pop values off the stack - LIFO results in reversal
mov r3, #0 // zero init counter Array
2:
pop {r0} // pop element value from stack - LIFO
str r0, [r1,r3]
add r3, r3, #4 // inc Array counter by 4 since word size is 4 bytes cmp r3, r2
blt 2b add sp, sp, #len.Array // restore stack pointer
GDB output:
(gdb) x/21d $r1
0x1102d: 1 2 3 4
0x1103d: 5 6 7 8
0x1104d: 9 10 11 12
0x1105d: 13 14 15 16
0x1106d: 32 64 128 256
0x1107d: 512
(gdb) x/21d $r1
0x1102d: 512 256 128 64
0x1103d: 32 16 15 14
0x1104d: 13 12 11 10
0x1105d: 9 8 7 6
0x1106d: 5 4 3 2
0x1107d: 1
.global reverse
.data
start: .word 1
end: .word 1
loopcount: .word 0
reverse:
ldr r3, =end
str r1, [r3]
next:
ldr r3,=end
ldr r2,=start
ldr r3, [r3]
ldr r2, [r2]
cmp r2,r3
bgt done
cmp r2,r3
beq done
sub r3,r2
mov r2,#0
mov r1,#0
loop:
cmp r2,r3
beq next2
add r2, r2, #1
add r1, r1, #4
b loop
next2:
ldr r3, [r0]
add r0, r0, r1
ldr r2, [r0]
str r3, [r0]
sub r0, r0, r1
str r2, [r0]
add r0, r0, #4
ldr r3,=end
ldr r1, [r3]
sub r1, r1, #1
str r1, [r3]
ldr r3,=start
ldr r1, [r3]
add r1, r1, #1
str r1, [r3]
b next
done:
bx lr
I am trying to reverse an array and this is my reverse function in assembly, the function is reverse(int data*,size); data is an array and size is the size. It works any array of size 5 but for longer arrays, for example of size 10, it will ignore the last 2 and act as if the array is of size 8 and swap it all as if the last 2 numbers in the array didn't exist, it would return:
Array:
1 2 3 4 5 6 7 8 9 10
My Return:
8 7 6 5 4 3 2 1 9 10
I can't seem to find out what my issue is.
Below is a crude and likely inefficient example of a reverse copy of one array to another; which may not be necessarily what you want but may foster some ideas.
Hardware : Marvell Armada 370/XP
model name : ARMv7 Processor rev 2 (v7l)
.bss
rArray: .zero
.data
Array: .word 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,32, 64, 128, 256, 512
.equ len.Array,.-Array
.text
.global main
main:
ldr r1,=Array // Array
mov r2, #len.Array // length of array
mov r3, #0 // zero init counter Array
ldr r4,=rArray // rArray
sub r5,r2, #4 // rArray counter - 1 element
1:
ldr r10, [r1,r3] // load word size element position x from Array
str r10, [r4,r5] // store word size element position x from Array into word size position y in rArray
add r3, r3, #4 // inc Array counter by 4 since word size is 4 bytes
subs r5, r5, #4 // decement rArray counter by 4 & get status (s)
bpl 1b // branch back to loop if positive or zero; i.e., N condition flag is clear
Results using GDB:
(gdb) x/21d $r1
0x1102d: 1 2 3 4
0x1103d: 5 6 7 8
0x1104d: 9 10 11 12
0x1105d: 13 14 15 16
0x1106d: 32 64 128 256
0x1107d: 512
(gdb) x/21d $r4
0x11082: 512 256 128 64
0x11092: 32 16 15 14
0x110a2: 13 12 11 10
0x110b2: 9 8 7 6
0x110c2: 5 4 3 2
0x110d2: 1