ARM assembly language: caesar cypher - arm

This is for homework
I have to take a given string and offset as parameters and create an encrypted version of the string. Here is what I have so far
.global
cypher:
stmfd sp!, {v1-v6, lr} #std
mov v1, a1 #hold the string pointer in v1
bl strlen #get the length of the string in a1
add a1, a1, #1 #add null byte space to strlen
mov v2, a1 #hold the length of space needed in v2
bl malloc #reserve space for new string in a1
mov v3, #0 #initial index of new string
loop:ldr v4, [v1], #4 #load v4 with string pointer and increment by bytes
add v5, v4, a2 #add the offset to the current character
str v5, [a1, v3] #store the new character in the new address
add v3, v3, #4 #increment the index by a byte
cmp v2, v3
bne loop
ldmfd sp!, {v1-v6, pc} #std
.end
I'm having trouble figuring out how to actually increment the character correctly. How to I add an offset to a character?(I'm guessing the ascii characters need to be incremented?)

You are iterating the loop by four bytes.
Below is the "correct" one: (and an optimize one, too: you don't need v3 and v5)
loop:ldrb v4, [v1], #1 #load v4 with string pointer and increment by bytes
subs v2, v2, #1
add v4, v4, a2 #add the offset to the current character
strb v4, [a1], #1 #store the new character in the new address
bne loop
ldmfd sp!, {v1-v6, pc} #std

Related

Bus error in ARMv7 assembly function to find maximum element of array

I'm having trouble with an ARMv7 assembly function I'm trying to write. The function is below.
.global maxF32
// float maxF32(const float x[], uint32_t count)
// returns the maximum value in the array (x) containing count entries
/* R0 = float x[], R1 = uint32_t count */
maxF32:
CMP R1, #0 # SET FLAGS OF COUNT
BEQ maxF32_end # IF COUNT == 0, GO TO END
MOV R2, R0 # COPY R0 INTO R2
MOV R0, #0 # ZERO OUT R0
MOV R3, #0 # ZERO OUT R3
MOV S0, R0 # ZERO OUT S0
MOV S1, R0 # ZERO OUT S1
MOV S2, R0 # ZERO OUT S2
B maxF32_loop # BRANCH TO LOOP
maxF32_loop:
CMP R1, #0 # CHECK IF COUNT == 0
BEQ maxF32_end # IF SO, GO TO END
VLDR.F32 S0, [R2] # LOAD CURRENT ELEMENT INTO S0
ADD R2, R2, #4 # INCREMENT VECTOR POINTER
VLDR.F32 S1, [R2] # LOAD NEXT ELEMENT INTO S1
SUB R1, R1, #1 # DECREMENT COUNT
CMP S0, S1 # SET FLAGS; CHECK S0 - S1
BMI maxF32_update # IF RESULT IS NEGATIVE (S1 > S0), GO TO UPDATE GREATEST
B maxF32_loop # REPEAT LOOP
maxF32_update:
VMOV R3, R1, S1 # MOVE GREATER INTO GREATEST REGISTER
B maxF32_loop # GO BACK TO LOOP
maxF32_end:
MOV R0, R3 # COPY GREATEST INTO R0
BX LR # RETURN
I test with the following C code:
extern float maxF32(const float x[], uint32_t count);
#define COUNT 3
float x[] = {1.2, 1.3, 1.4};
float result;
result = maxF32(x, COUNT);
printf("result is %lf\n", result);
Using gdb, right around the second to last or last loop through the array, I get a "bus error" right around the CMP S0, S1 line. I sometimes also get an "expected comma" at MOV R3, R1, S1, which confuses me as I don't know where I would need an extra comma.
Last note, I am coding on a Raspberry Pi Model 3 B+.
Thanks for any and all help.
On a count of "3" you compare s0 to s1 3 times.... meaning you look for four elements in the array. (With n elements you really should only have n-1 comparisons)
The logic...
decrement count
cmp element0 element1 ... loop
decrement count
compare element1 element2 ... loop
decrement count
compare element2 with 'bus error' -- nothing there.
Moving SUB R1, R1, #1 to the first line after maxF32_loop: probably fixes it as it puts the decrement before the check for count being 0.

Why is my min and max value for the array incorrect? ARM Assembly

I am writing a program that creates an array of 10 random integers between 0 and 999. My code for creating and occupying the array is functioning properly but when I attempt to print out the minimum and maximum value of the array, it prints the wrong value.
This is the code where I read through my array and print out each value. The spaced section is where I look for the min and max:
main:
BL _seedrand # seed random number generator with current time
MOV R0, #0 # initialze index variable
MOV R3, #1000
MOV R5, #-1
PUSH {R3}
PUSH {R5}
readloop:
CMP R0, #10 # check to see if we are done iterating
BEQ readdone # exit loop if done
LDR R1, =a # get address of a
LSL R2, R0, #2 # multiply index*4 to get array offset
ADD R2, R1, R2 # R2 now has the element address
LDR R1, [R2] # read the array at address
POP {R5}
CMP R5, R1
MOVGT R5, R1
POP {R3}
CMP R3, R1
MOVLT R3, R1
PUSH {R3}
PUSH {R5}
PUSH {R0} # backup register before printf
PUSH {R1} # backup register before printf
PUSH {R2} # backup register before printf
MOV R2, R1 # move array value to R2 for printf
MOV R1, R0 # move array index to R1 for printf
BL _printf # branch to print procedure with return
POP {R2} # restore register
POP {R1} # restore register
POP {R0} # restore register
ADD R0, R0, #1 # increment index
B readloop # branch to next loop iteration
readdone:
MOV R1, R3
LDR R0, =min_str # R0 contains formatted string address
BL printf
MOV R1, R5
LDR R0, =max_str
BL printf
B _exit
If you would like to see the rest of the code where the array is created and populated, I can do so. I have tried different tags and backing up R3 and R5 on the stack and it still prints the wrong values. Specifically the min value will always print the last integer in the array and the max is always printed as 0.

Caesar decoder in ARM Assembly

As it said in the title, my objective is to write a program in C and ARM assembly that decodes a string by shifting the byte value of each character by a certain amount. The "space" character isn't shifted, instead just copied over to the resulting string. The process ends when the null-terminator is located.
Here is my C code:
#include <stdio.h>
extern void init(char * encrypt);
extern char * decrypt(char * encrypt, int shift);
int main(int argc, char * argv[])
{
char * result;
char encrypt[] = "GSRKVEXYPEXMSRW CSY LEZI JSYRH XLI WLMJX ZEPYI";
int i;
init(encrypt);
for (i = 1; i < 5; i++) {
result = decrypt(encrypt, i);
printf("Possible decrypt with shift %d: %s\n", i, result);
}
}
Here is my ARM code (this is all in one file called decrypt.s):
# init: reserves space for the decryption
.global init
.text
init: stmfd sp!, {v1-v6, lr}
mov v1, a1
bl strlen
bl malloc
bufferAddr: .fill 4, 1, 0
str a1, bufferAddr
#mov a2, v1
#bl strcpy
ldmfd sp!, {v1-v6, pc}
# decrypt: performs shifting of letters to decrypt string
.global decrypt
.text
decrypt: stmfd sp!, {v1-v6, lr}
mov v1, a1 # v1 is the pointer to encrypt (string)
ldr v2, =bufferAddr # v2 is the pointer to result (string)
loop:
ldrb v3, [v1], #1 # v3 is the current char (8-bit number)
cmp v3, #0
streqb v3, [v2], #1
beq endLabel
cmp v3, #32 # check if v3 == "space"
streqb v3, [v2], #1 # if true, store space in result, increment
beq loop # if true, proceed to next char
sub v3, v3, a2 # shift v3 by shift-value
cmp v3, #65 # check if v3 >= 65 (A)
strgeb v3, [v2], #1 # if true, store char in result, increment
bge loop
# if less than A
add v3, v3, #26 # add 26, wrap between A-Z
strb v3, [v2], #1 # if true, store char in result, increment
b loop
endLabel:
ldr a1, =bufferAddr
ldmfd sp!, {v1-v6, pc}
.end
The problem is, it only goes through the loop once, then it gets stuck. Sometimes it prints an error along the lines of "sim: unknown SWI..." or "unknown v6 isbn...". Or worst of all, it just prints nothing (infinite loop?)
I'm not sure what the problem is, my logic seems to make sense.
I read the next byte:
If it's null-terminator, I put it in the resulting string as well, and end the loop.
If it's space, I put the space in the resulting string, and continue the loop.
If it's >= 65 (which it SHOULD be, unless Space/null-terminator), I subtract the shift-value. If the resulting value is >= 65, I put it in the resulting string. If it's < 65, I add 26, then put it in the resulting string, therefore successfully wrapping to the capital letters of the alphabet.
There is (should be) no other case.
Yet I still get errors, or possibly an infinite loop. Any ideas?
str a1, bufferAddr stores the value from the register at the memory location pointed to by bufferAddr. Since this is in the middle of the init function it works first time only.
However ldr v2, =bufferAddr loads the value of bufferAddr, this results in in the result overwriting decrypt.
You should use ldr v2, bufferAddr.

STRB works, unless target address gets shifted

I'm trying to use ARM assembly to insert one string into another, however my code would always return an empty string to the C program calling the assembly program. I believe I have narrowed down my issue to the STRB instruction. Below is my code with most irrelevant code removed. The important part to look at is in the "test" block.
.global ins
ins:
stmfd sp!, {v1-v6, lr}
mov v1, a1 # save pointer to 1st string
mov v2, a2 # save pointer to 2nd string
bl strlen # find out length
mov v3, a1 # save string1 length
mov a1, v2 # recover pointer to string 2
bl strlen # length of string 2
add a1, a1, v3 # total length
add a1, a1, #1 # add one for null byte
bl malloc
add a3, a3, #1
test:
ldrb v3, [v1], #1
strb v3, [a1], #1
ldmfd sp!, {v1-v6, pc}
exit:
.end
v1 and v2 hold strings 1 and 2. When I have the test block written as:
test:
ldrb v3, [v1], #1
strb v3, [a1], #1
ldmfd sp!, {v1-v6, pc}
then the program returns an empty string. However, if I have it written as:
test:
ldrb v3, [v1], #1
strb v3, [a1]
ldmfd sp!, {v1-v6, pc}
it successfully returns the first character in string 1. Obviously, this is not sufficient to build a new string, as I'm not performing an offset on a1.
Does anyone know what is causing the string to be returned as empty? I honestly have no idea what the issue may be after several hours of experimenting and researching.
Any help is greatly appreciated!
The value in a1 is returned to the C function calling your assembler routine. You need to return the address of the start of the string, but if you increment a1 while writing the string you will return the address of the end of the string instead.
If you use another register for storing the current address that you are writing to then the start address will still be in a1 when you return. e.g:
test:
mov v4, a1 # copy address of new string to v4
ldrb v3, [v1], #1
strb v3, [v4], #1 # increment v4, the start of string
# will still be in a1
ldmfd sp!, {v1-v6, pc}

Printf Change values in registers, ARM Assembly

I'm new to assembly programing and I'm programing for ARM.
I'm making a program with two subroutines: one that appends a byte info on a byte vector in memory, and one that prints this vector. The first address of the vector contains the number of elements that follows, up to 255. As I debug it with GDB, I can see that the "appendbyte" subroutine works fine. But when it comes to the "printvector" one, there are some problems. First, the element loaded in register r1 is wrong (it loads 0, when it should be 7). Then, when I read the registers values with GDB after I use the "printf" function, a lot of register get other values that weren't supposed to change, since I didn't modify them, I just used "printf". Why is "printf" modyfing the values.
I was thinking something about the align. I'm not sure if i'm using the directive correctly.
Here is the full code:
.text
.global main
.equ num, 255 # Max number of elements
main:
push {lr}
mov r8, #7
bl appendbyte
mov r8, #5
bl appendbyte
mov r8, #8
bl appendbyte
bl imprime
pop {pc}
.text
.align
printvector:
push {lr}
ldr r3, =vet # stores the address of the start of the vector in r3
ldr r2, [r3], #1 # stores the number of elements in r2
.align
loop:
cmp r2, #0 #if there isn't elements to print
beq fimimprime #quit subroutine
ldr r0, =node #r0 receives the print format
ldr r1, [r3], #1 #stores in r1 the value of the element pointed by r3. Increments r3 after that.
sub r2, r2, #1 #decrements r2 (number of elements left to print)
bl printf #call printf
b loop #continue on the loop
.align
endprint:
pop {pc}
.align
appendbyte:
push {lr}
ldr r0, =vet #stores in r0 the beggining address of the vector
ldr r1, [r0], #1 #stores in r1 the number of elements and makes r0 point to the next address
add r3, r0, r1 #stores in r3 the address of the first available position
str r8, [r3] #put the value at the first available position
ldr r0, =vet #stores in r0 the beggining address of the vector
add r1, r1, #1 # increment the number of elements in the vector
str r1, [r0] # stores it in the vector
pop {pc}
.data # Read/write data follows
.align # Make sure data is aligned on 32-bit boundaries
vet: .byte 0
.skip num # Reserve num bytes
.align
node: .asciz "[%d]\n"
.end
The problems are in
ldr r1, [r3], #1
and
bl printf
I hope I was clear on the problem.
Thanks in advance!
The ARM ABI specifies that registers r0-r3 and r12 are to be considered volatile on function calls. Meaning that the callee does not have to restore their value. LR also changes if you use bl, because LR will then contain the return address for the called function.
More information can be found on ARMs Information Center entry for the ABI or in the APCS (ARM Procedure Call Standard) document.
printvector:
push {lr}
ldr r3, =vet # stores the address of the start of the vector in r3
ldr r2, [r3], #1 # stores the number of elements in r2
.align
loop:
cmp r2, #0 #if there isn't elements to print
beq fimimprime #quit subroutine
ldr r0, =node #r0 receives the print format
ldr r1, [r3], #1 #stores in r1 the value of the element pointed by r3. Increments r3 after that.
sub r2, r2, #1 #decrements r2 (number of elements left to print)
bl printf #call printf
b loop #continue on the loop
.align
endprint:
pop {pc}
that is definitely not how you use align. Align is there to...align the thing that follows on some boundary (specified in an optional argument, note this is an assembler directive, not an instruction) by padding the binary with zeros or whatever the padding is. So you dont want a .align in the code flow, between instructions. You have done that between the ldr r1, and the cmp r2 after loop. Now the align after b loop is not harmful as the branch is unconditional but at the same time not necessary as there is no reason to align there the assembler is generating an instruction flow so the bytes cant be unaligned. Where you would use .align is after some data declaration before instructions:
.byte 1,2,3,4,5,
.align
some_code_branch_dest:
In particular one where the assembler complains or the code crashes.

Resources