I am writing an LC3 program that increments each letter of a three-letter word stored in memory following the program. 'a' becomes 'd', 'n' becomes 'q', 'z' becomes 'c', etc.
I am using this as LC3 Assembly a reference
Here is my code so far
.orig x3000
ADD R1, R1, #3
LEA R2, STRING
HALT
STRING .STRINGZ "anz"
.END
I was able to figure out how to declare a string of characters in LC3 from my reference. However does anyone how to do the actual incrementation or have any references that I could use to figure out how to do it?
Using a while loop, I was able to get it to increment each char of the string until a null value is found. I didn't code it to loop back around (z becoming c) but this should get you started.
;tells simulator where to put my code in memory(starting location). PC is set to thsi address at start up
.orig x3000
MAIN
AND R1, R1, #0 ; clear our loop counter
WHILE_LOOP
LEA R2, STRING ; load the memory location of the first char into R1
ADD R2, R2, R1 ; Add our counter to str memory location. R2 = mem[R1 + R2]
LDR R3, R2, #0 ; Loads the value stored in the memory location of R2
BRz END_WHILE ; If there is no char then exit loop
ADD R3, R3, #3 ; change the char
STR R3, R2, #0 ; store the value in R3 back to the location in R2
ADD R1, R1, #1 ; add one to our loop counter
BR WHILE_LOOP ; jump to the top of our loop
END_WHILE
HALT
; Stored Data
STRING .STRINGZ "anz"
.END
Related
I have generated an array of random integers between 0 and 256 and I tried to sort them using an insertion sort however at some point along the line I messed up and got an error "segmentation fault (core dumped)
I have no idea exactly why I am getting this but I believe the problem has something to do with the macro j representing a loop counter. I have been working away at this for a few hours and I have been stuck on this for a while.
EDIT: After using the debugger I have isolated the problem to be the line:
bl printf
right at the very end when it tries to print the second sorted value.
I have tried to allocate more ram up to 416 bytes, I have tried moving the top2 loop label around (which is the loop that uses j as it's counter) and the farthest i have gotten is for the program to print the first element of the sorted array and then give the error
ALLOC =-(16+400*1)&-16
.equ DEALLOC, -ALLOC
size = 50
define(arraybase, x19)
i .req x20
define(j, x21)
define(temp, w22)
define(sort1, w23)
print1: .asciz "Array[%d]: %d\n"
print2: .string "\nSorted Array: \n"
print3: .asciz "top value equals %d \n"
...
mov i, 0
top1: add i, i, 1
ldrb temp, [arraybase, i ]
mov j, i
top2: mov x25, j
sub x25, x25, 1
ldrb sort1, [arraybase, x25 ]
cmp temp, sort1
b.ge skip1
strb sort1, [arraybase, j]
skip1: sub j, j, 1
cmp j, 0
b.gt top2
strb temp, [arraybase, j]
cmp i, size-1
b.lt top1
printing:
ldr x0, =print2
bl printf
mov i, 0
ldr x0, =print1
tprint: mov x1, i
ldrb w2, [arraybase, i]
bl printf
add i, i, 1
cmp i, size-1
b.le tprint
mov x0, 0
ldp x29, x30, [sp], DEALLOC
ret
The array should be printed in the random order it was initialized in, then it should print the value at the top of the array, then it is meant to print the sorted array in increasing order.
The exact error message I got was:
Segmentation fault (core dumped)
This appears after it prints the first value of the sorted array
So I'm a bit of a beginner to ARM Assembly (assembly in general, too). Right now I'm writing a program and one of the biggest parts of it is that the user will need to type in a letter, and then I will compare that letter to some other pre-inputted letter to see if the user typed the same thing.
For instance, in my code I have
.balign 4 /* Forces the next data declaration to be on a 4 byte segment */
dime: .asciz "D\n"
at the top of the file and
addr_dime : .word dime
at the bottom of the file.
Also, based on what I've been reading online I put
.balign 4
inputChoice: .asciz "%d"
at the top of the file, and put
inputVal : .word 0
at the bottom of the file.
Near the middle of the file (just trust me that there is something wrong with this standalone code, and the rest of the file doesn't matter in this context) I have this block of code:
ldr r3, addr_dime
ldr r2, addr_inputChoice
cmp r2, r3 /*See if the user entered D*/
addeq r5, r5, #10 /*add 10 to the total if so*/
Which I THINK should load "D" into r3, load whatever String or character the user inputted into r2, and then add 10 to r5 if they are the same.
For some reason this doesn't work, and the r5, r5, #10 code only works if addne comes before it.
addr_dime : .word dime is poitlessly over-complicated. The address is already a link-time constant. Storing the address in memory (at another location which has its own address) doesn't help you at all, it just adds another layer of indirection. (Which is actually the source of your problem.)
Anyway, cmp doesn't dereference its register operands, so you're comparing pointers. If you single-step with a debugger, you'll see that the values in registers are pointers.
To load the single byte at dime, zero-extended into r3, do
ldrb r3, dime
Using ldr to do a 32-bit load would also get the \n byte, and a 32-bit comparison would have to match that too for eq to be true.
But this can only work if dime is close enough for a PC-relative addressing mode to fit; like most RISC machines, ARM can't use arbitrary absolute addresses because the instruction-width is fixed.
For the constant, the easiest way to avoid that is not to store it in memory in the first place. Use .equ dime, 'D' to define a numeric constant, then you can use
cmp r2, dime # compare with immediate operand
Or ldr r3, =dime to ask the assembler to get the constant into a register for you. You can do this with addresses, so you could do
ldr r2, =inputVal # r2 = &inputVal
ldrb r2, [r2] # load first byte of inputVal
This is the generic way to handle loading from static data that might be too far away for a PC-relative addressing mode.
You could avoid that by using a stack address (sub sp, #16 / mov r5, sp or something). Then you already have the address in a register.
This is exactly what a C compiler does:
char dime[4] = "D\n";
char input[4] = "xyz";
int foo(int start) {
if (dime[0] == input[0])
start += 10;
return start;
}
From ARM32 gcc6.3 on the Godbolt compiler explorer:
foo:
ldr r3, .L4 # load a pointer to the data section at dime / input
ldrb r2, [r3]
ldrb r3, [r3, #4]
cmp r2, r3
addeq r0, r0, #10
bx lr
.L4:
# gcc greated this "literal pool" next to the code
# holding a pointer it can use to access the data section,
# wherever the linker ends up putting it.
.word .LANCHOR0
.section .data
.p2align 2
### These are in a different section, near each other.
### On Godbolt, click the .text button to see full assembler directives.
.LANCHOR0: # actually defined with a .set directive, but same difference.
dime:
.ascii "D\012\000"
input:
.ascii "xyz\000"
Try changing the C to compare with a literal character instead of a global the compiler can't optimize into a constant, and see what you get.
i am facing a problem that I could not resolve so i have to turn to the community to help me out. The problem is related to PPC function hooking.
The area where i am hooking is this.
.text:8220D810 mflr r12
.text:8220D814 bl __savegprlr_20
.text:8220D818 stfd f31, var_70(r1)
.text:8220D81C stwu r1, -0x100(r1)
.text:8220D820 lis r11, off_82A9CCC0#ha // => This is where i am hooking the function
.text:8220D824 lis r22, dword_82BBAE68#ha // These 4 instructions are overwritt
.text:8220D828 lis r10, 8 # 0x87700 //Patched
.text:8220D82C mr r26, r3 //Patched
.text:8220D830 li r20, 0
.text:8220D834 lwz r9, off_82A9CCC0#l(r11)
.text:8220D838 ori r23, r10, 0x7700 # 0x87700
.text:8220D83C lwz r11, dword_82BBAE68#l(r22)
.text:8220D840 cmplwi cr6, r11, 0
.text:8220D844 stw r9, 0x100+var_7C(r1)
.text:8220D848 bne cr6, loc_8220D854
.text:8220D84C mr r30, r20
.text:8220D850 b loc_8220D85C
Here it jumps to my code cave that is mentioned below. The patched instructions are correctly written in the PredictPlayerHook function and is not the problem.
The problem here is if i call a function in the hook e.g here i call "GetCurrentCmdNumber(0);" it causes the game to crash. Now without calling any functions the game doesn't crash and the code cave works without any issues. but if I try to call any function within the code cave(PredictPlayerHook) it just crashes. I cant debug it so i dont know where it crashes.
void __declspec(naked) PredictPlayerHook(){
DWORD R11,Return,cmdNumber;
__asm lis r11, 0x82AA //patched instructions
__asm lis r22, 0x82BC //patched instructions
__asm lis r10, 0x8 //patched instructions
__asm mr r26, r3 //patched instructions
__asm mflr r0 ; //mflr grabs the link register, and stores it into the first operand. r0 is now the link register
__asm stw r0, -0x14(r1) ; //Save the link register inside the stack frame
__asm stwu r1, -0x90(r1) ;// This is pushing the stack (hence push)
// cmdNumber = GetCurrentCmdNumber(0);
__asm addi r1, r1, 0x90 ;//popping the stack frame
__asm lwz r0,-0x14(r1) ; //Reading the link register from the sack
__asm mtlr r0
__asm stw r11,R11
//Return = 0x82200230;
__asm lis r11,0x8220 //Return Address is correct. The difference is in IDA segment, it is +0xD600 ahead of the original address.
__asm ori r11,r11,0x0230
__asm mtctr r11
__asm lwz r11,R11
__asm bctr
}
Here is the function itself and its correct. I can use it in a hook placed else where in the game so it has no issues.
typedef int (__cdecl* CL_GetCurrentCmdNumber)(int localClientNum);
CL_GetCurrentCmdNumber GetCurrentCmdNumber = (CL_GetCurrentCmdNumber)0x82261F90;
So I believe that the way I store the string works. I am just having some issues passing the String out of the subroutine. I heard that in order to pass something out of a subroutine you need to store it in R1 but I can't get it to store into my WORD array
.orig x3000
AND R1,R1,0
LEA R0,PROMPT
PUTS
JSR GETS
ST R1,WORD
LEA R0,WORD
PUTS
halt
; ---------Data Area-------------
WORD .blkw 20
PROMPT .stringz "Enter String: "
; -------------------------------
GETS LEA R1,MEMORYBLOCK ; saves the address of the storage memory block
loop GETC ; input character -> r0
PUTC ; r0 -> console
; always points at the next available block
LD R2,EMPTY ; check for
ADD R2,R2,R0 ; end of line
BRz finish
LD R2,COUNTDOWN
ADD R2,R2,#-1
BRz finish
ST R2,COUNTDOWN
STR R0,R1,#0 ; r0 -> ( memory address stored in r1 + 0 )
ADD R1,R1,#1 ; increments the memory pointer so that it
BR loop
finish LEA R1,MEMORYBLOCK
RET
; ----Subroutine Data Area-------
EMPTY .fill xfff6
COUNTDOWN .fill #10
MEMORYBLOCK .BLKW 20
; -------------------------------
.end
The biggest problem here is the concept of "returning a string". What you're actually doing at the end of GETS is returning the memory address at which the string starts. When you then store this into WORD in the calling function, you are storing the memory address of the first byte of the string that was input (i.e. the memory address of MEMORYBLOCK) into the first byte of WORD. You aren't copying the entire string from MEMORYBLOCK into WORD.
The easiest "fix" for what you're trying to do would be to change
LEA R0,WORD
to
LD R0,WORD
and then for good measure:
WORD .blkw 20
to
WORD .fill 0
as now you're just using it to store a single value (i.e. the memory address of MEMORYBLOCK).
However, at this point you haven't made a copy of the string. If you want to do this, then you will need to make a loop whereby you walk through MEMORYBLOCK and copy each byte to WORD instead.
The final, cheaper, way to do this is to just use MEMORYBLOCK directly from the calling function. It's not really any less valid in a program of this size, unless there's project requirements that ask otherwise.
I'm trying to get modulo of addition of two numbers with ARM 32-bit processor. Well, I'm trying to make it with three unsigned long 128 bit numbers but I cant succeed. Can anyone give me an idea or basic example of it?
mov r1, #11
mov r2, #13
mov r3, #15
add r1, r1,r2
subge r1, r1, r3
ldr lr, address_of_return2
ldr lr, [lr]
bx lr
You need cmp r1,r3 between add and subge. First add, than test if greater than modulo, finally substract if greater or equal (assuming both input numbers are less than modulo).
PS: Or cmp r3,r1.... not sure by the order right now.