I have a problem with this LC-3 program, I can't get the string to display from the if/else statement. I don't know if I'm doing the statement wrong, or if I am displaying the string wrong. The goal is to have it display the IF when the user enters 0 and the else (halt the program) when they enter a 1.
.ORIG x3000
START:
; clear registers
AND R0, R0, 0
AND R1, R0, 0
AND R2, R0, 0
AND R3, R0, 0
AND R4, R0, 0
; print greeting
LEA R0, GREETING
PUTS
; get user-input
; echo it back
GETC
PUTC
; store entered string
ST R0, USERINPUT
;FIRST IF STATEMENT
OUTPUT LD R2, USERINPUT
BRz ENDIF
LEA R3, GREETING
;ELSE
ENDIF
LD R2, USERINPUT
HALT
DONE
; stop the processor
HALT
GREETING: .STRINGZ "\nWelcome to the game.\nDo you want to play?\n0:Yes 1:No\n: "
GREETINGTWO: .STRINGZ "\nTest if statement: "
; variables
USERINPUT: .FILL 0
; end of code
.END
You're displaying the string incorrectly.
LEA only loads the effective address of a label/memory offset, it does not print it out. If you want to print out a string, you must call TRAP x22 (macroed to PUTS), as in the 14th line of your code snippet above.
Related
I'm doing a blackjack game for my final project for an assembly course. I have an array of words that represents 52 cards in a deck. My game wont be exactly like blackjack, but I need to demonstrate the basic concept of the game.
I'm trying to loop my deal function twice, but no matter what value I put into r4 (the loop counter) it only prints the output of the deal function once. I've looked at this in GDB and after the first iteration of deal I get an error:
[Inferior 1 (process 1585) exited with code 04]
mov r4, #0
cmp r4, #4
beq display_2
add r4, r4, #1
bal deal
Whole source code:
.equ INPUT, 0
.equ OUTPUT, 1
.equ LOW, 0
.equ HIGH, 1
.equ PIN0, 0 // wipi pin 0 - bcm 17
.equ PIN1, 1 // wipi pin 1 - bcm 18
.equ PIN2, 2 // wipi pin 2 - bcm 27
.equ PIN3, 3 // wipi pin 3 - bcm 22
.equ PIN4, 4 // wipi pin 4 - bcm 23
.equ PIN5, 5 // wipi pin 5 - bcm 24
.equ PIN6, 6 // wipi pin 6 - bcm 25
.equ PIN7, 7 // wipi pin 7 - bcm 4
.global main
.data
format: .asciz "r1=%d\n"
.balign 4
// Create a deck of 52 cards
deck:
.word 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10
.word 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10
.word 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10
.word 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10
.text
// ripped from C++ compiler's assembly output
.align 2
.L3: .word 1321528399
main:
push {lr}
bl wiringPiSetup
mov r0, #PIN0
mov r1, #OUTPUT
bl pinMode
mov r0, #PIN1
mov r1, #OUTPUT
bl pinMode
mov r0, #PIN2
mov r1, #OUTPUT
bl pinMode
mov r0, #PIN3
mov r1, #OUTPUT
bl pinMode
mov r0, #PIN4
mov r1, #OUTPUT
bl pinMode
deal:
// the following code was disassembled from the C++ compiler's
// rand function
mov r0, #0
bl time
mov r3, r0
mov r0, r3
bl srand
bl rand
mov r2, r0
ldr r3, .L3
smull r1, r3, r3, r2
mov r1, r3, asr #4
mov r3, r2, asr #31
rsb r3, r3, r1
mov r1, #52
mul r3, r1, r3
rsb r3, r3, r2
// end of C++ compiler's code
ldr r0, =format
// mov the random number generated (r3) into r1 for printing
mov r1, r3
// take the same value and store it also into r7 to preserve it
mov r7, r1
bl printf
ldr r0, =format
ldr r1, =deck
// setup r9 as the increment value leading to the next index
// of the array
mov r9, #4
// multiply into r8 the random number times the increment value
// of the array (4 bytes)
mul r8, r7, r9
// r8 now holds the randomized card just dealt to the player
// add this to the players score and get the actual value
// at from the address
add r1, r1, r8
ldr r1, [r1]
// mov into r7 the players score to preserve it
mov r7, r1
bl printf
display_2:
mov r4, #0
l:
cmp r4, #2
bne deal
add r4, r4, #1
bal l
// write the players score to the led display
mov r0, r7
bl digitalWriteByte
Sample output:
pi#raspberrypi:~ $ ./6leds.out
r1=50 // the random index chosen
r1=10 // the value stored at that array index
pi#raspberrypi:~ $ ./6leds.out
r1=6
r1=7
pi#raspberrypi:~ $ ./6leds.out
r1=6
r1=7
^ I would like it to do this twice instead of once
A loop might be structured like so:
// Initialize loop counter. Note this is outside the loop body.
mov #r4, 0
loop_entry:
// Test if the loop is done. This is a "while (...) { }" or for style loop
cmp #r4, <loop_limt>
bge loop_exit
// code that you want to execute multiple times.
// In the above this would be everything between deal: and display_2:
<...>
add r4, r4, #1
bal loop_entry
loop_exit:
// Do stuff after the loop.
In the code you posted, the initialization to zero effectively happens inside of the loop. I would expect this to produce an infinite loop, not one which terminates after one execution. (E.g. I don't see how the bal l ever gets executed. You can verify this by stepping through in the debugger.)
The only simple thing I can think of that you might be getting hung up on is the difference between labels and functions. In the code you posted, the only label that identifies a function is main:. Elsewhere, the code just keeps executing past a label in a straight line. (There is of course nothing special about the main: label either, it is how it is used.) So after the second printf following deal:, the move r4, #0 under display_2: gets executed.
My CPU is arm.How can I figure out the function parameter value if it's optimized out?
For example:
status_t NuPlayer::GenericSource::setDataSource(
int fd, int64_t offset, int64_t length) {
resetDataSource();
mFd = dup(fd);
mOffset = offset;
mLength = length;
Above function has 3 parameters, when I try to print the second parameter offset, I will get below result:
Thread 4 "Binder:15082_3" hit Breakpoint 1, android::NuPlayer::GenericSource::setDataSource (this=0xae63bb40, fd=8, offset=<optimized out>, length=9384436) at frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp:123
123 resetDataSource();
(gdb) x/i $pc
=> 0xb02aaa80 <android::NuPlayer::GenericSource::setDataSource(int, long long, long long)+12>: blx 0xb0282454 <_ZN7android8NuPlayer13GenericSource15resetDataSourceEv#plt>
(gdb) n
125 mFd = dup(fd);
(gdb) print offset
$1 = <optimized out>
(gdb) p $eax
$2 = void
(gdb) disassemble /m
Dump of assembler code for function android::NuPlayer::GenericSource::setDataSource(int, long long, long long):
122 int fd, int64_t offset, int64_t length) {
0xb02aaa74 <+0>: push {r4, r5, r6, r7, lr}
0xb02aaa76 <+2>: sub sp, #4
0xb02aaa78 <+4>: mov r4, r3
0xb02aaa7a <+6>: mov r5, r2
0xb02aaa7c <+8>: mov r6, r1
0xb02aaa7e <+10>: mov r7, r0
123 resetDataSource();
=> 0xb02aaa80 <+12>: blx 0xb0282454 <_ZN7android8NuPlayer13GenericSource15resetDataSourceEv#plt>
124
125 mFd = dup(fd);
0xb02aaa84 <+16>: mov r0, r6
0xb02aaa86 <+18>: blx 0xb027e5d8 <dup#plt>
0xb02aaa8a <+22>: ldrd r2, r1, [sp, #24]
0xb02aaa8e <+26>: str.w r0, [r7, #224] ; 0xe0
0xb02aaa92 <+30>: movs r0, #0
126 mOffset = offset;
0xb02aaa94 <+32>: strd r5, r4, [r7, #232] ; 0xe8
127 mLength = length;
0xb02aaa98 <+36>: strd r2, r1, [r7, #240] ; 0xf0
128
129 // delay data source creation to prepareAsync() to avoid blocking
130 // the calling thread in setDataSource for any significant time.
131 return OK;
0xb02aaa9c <+40>: add sp, #4
0xb02aaa9e <+42>: pop {r4, r5, r6, r7, pc}
End of assembler dump.
(gdb)
I guess it's in some register but the result of $eax is void.
I guess it's in some register but the result of $eax is void.
There is no register called eax on ARM.
To know which register the parameter is in, you need to know calling convention.
Looks like you are using 32-bit ARM. From above link:
r0 to r3: used to hold argument values passed to a subroutine
So you should do info registers, verify that r0 == 0xae63bb40, r1 == 8 and find the offset in r2.
Sounds like example code has assigned the parameter variable to local variable already, so print that value will be exactly the same as optimized out parameters.
mOffset = offset;
mLength = length;
I have small application that compiles and runs well on my ARM Cortex M4. But when I disassemble binary file, that I flush, here is how first bytes look like:
00000000 <.data>:
0: 20020000 andcs r0, r2, r0
4: 080003b5 stmdaeq r0, {r0, r2, r4, r5, r7, r8, r9}
8: 08000345 stmdaeq r0, {r0, r2, r6, r8, r9}
c: 08000351 stmdaeq r0, {r0, r4, r6, r8, r9}
080003b5 should be the address of Reset handler (I have .word Reset_Handler there), but disassembling ELF shows that Reset handler is actually located at 080003b4, which is 1 byte before:
080003b4 <Reset_Handler>:
80003b4: 2100 movs r1, #0
80003b6: e003 b.n 80003c0 <InitData>
(It's running in THUMB mode, I have 2byte instructions).
Even if I disassemble the binary file, it's located at 080003b4:
000003b4 <.data+0x3b4>:
3b4: 2100 movs r1, #0
3b6: e003 b.n 0x3c0
My question is, why does it point 1 byte after? This code surprisingly works on actual board. Even without disassembling, shouldn't instructions be aligned by 2 byte? how can address be 0x000003b5?
Answer: ARM uses it for switching to THUMB mode.
I had worked out some code for my assignment and something tells me that I'm not doing it correctly.. Hope someone can take a look at it.
Thank you!
AREA Reset, CODE, READONLY
ENTRY
LDR r1, = 0x13579BA0
MOV r3, #0
MOV r4, #0
MOV r2, #8
Loop CMP r2, #0
BGE DONE
LDR r5, [r1, r4]
AND r5, r5, #0x00000000
ADD r3, r3, r5
ADD r4, r4, #4
SUB r2, r2, #1
B Loop
LDR r0, [r3]
DONE B DONE
END
Write an ARM assembly program that will add the hexadecimal digits in register 1 and save the sum in register 0. For example, if r1 is initialized as follows:
LDR r1, =0x120A760C
When you program has run to completion, register 0 will contain the sum of 1+2+0+A+7+6+0+C.
You will need to use the following in your solution:
· An 8-iteration loop
· Logical shift right instruction
· The AND instruction (used to force selected bits to 0)
I know that I did not even use LSR. where should I put it? I'm just getting started on Assembly hope someone makes some improvements on this code..
I'm getting very mad at this and can't figure out why my BEQ statement is always executed.
The program should replace char located in memory(Address in RO)
_ should become +
C should become A
A should become B
B should become C
This is what I have so far (sorry french comments):
MOV R11, #0 ; Initialise le nombe de copie fait
MOV R10, #43 ; R10 = +
MOV R9, #'_' ; R9 = _
MOV R8, #'A' ; R8 = A
MOV R7, #'B' ; R7 = B
MOV R6, #'C' ; R6 = C
TOP:
LDRB R5, [R0, R11] ; Copie element X dans R5
CMP R5, R9
BEQ PLUS
CMP R5, R8
BEQ A
CMP R5, R7
BEQ B
CMP R5, R6
BEQ C
PLUS: ; Branchement si _
STRB R10, [R0, R11]
A: ; Branchement si A
STRB R8, [R0, R11]
B: ; Branchement si B
STRB R7, [R0, R11]
C: ; Branchement si C
STRB R6, [R0, R11]
ADDS R11, R11, #1 ; ++nbcopiefait
CMP R11, R1 ; Validation de la condition
BNE TOP
Apparently it's not only C's switch() that confuses people...
So, what you're currently doing is the equivalent of
for (size_t i = 0; i < n; i++)
{
switch(chararray[i])
{
default:
case '_': chararray[i] = '+';
case 'C': chararray[i] = 'A';
case 'A': chararray[i] = 'B';
case 'B': chararray[i] = 'C';
}
}
You're missing the break; after every case.
Edit, because it seems I have to make it really obvious:
for (size_t i = 0; i < n; i++)
{
switch(chararray[i])
{
default:
break;
case '_': chararray[i] = '+';
break;
case 'C': chararray[i] = 'A';
break;
case 'A': chararray[i] = 'B';
break;
case 'B': chararray[i] = 'C';
break; //unnecessary, but I put it in for regularity
}
}
To expand on EOF's answer, you can see what's going on by tracing through a sample execution instruction-by-instruction - a debugger always helps, but this is simple enough to do by hand. Let's consider a couple of different situations:
Instruction case char=='A' case char=='Z'
-------------------------------------------------------------------
...
LDRB R5, [R0, R11] executes, r5='A' executes, r5='Z'
CMP R5, R9 executes, flags=ne executes, flags=ne
BEQ PLUS flags!=eq, not taken flags!=eq, not taken
CMP R5, R8 executes, flags=eq executes, flags=ne
BEQ A flags==eq, taken flags!=eq, not taken
CMP R5, R7 / executes, flags=ne
BEQ B / flags!=eq, not taken
CMP R5, R6 / executes, flags=ne
BEQ C / flags!=eq, not taken
PLUS: STRB R10, [R0, R11] V executes: oops!
A: STRB R8, [R0, R11] executes executes: oops!
B: STRB R7, [R0, R11] executes: oops! executes: oops!
C: STRB R6, [R0, R11] executes: oops! executes: oops!
ADDS R11, R11, #1 executes executes
...
So no matter what happens, everything ends up as 'C' regardless! (note there's a register mixup for 'A', 'B', and 'C' - if you match r8, you jump to storing r8, etc.) Implementing the equivalent of break is a case of making sure instructions are skipped when you don't want them executing:
...
CMP R5, R6
BEQ C
B LOOP ; no match, skip everything
PLUS: STRB R10, [R0, R11]
B LOOP ; we've stored '_', skip 'B', 'C', and 'A'
A: STRB R7, [R0, R11]
B LOOP ; we've stored 'B', skip 'C' and 'A'
B: STRB R6, [R0, R11]
B LOOP ; we've stored 'C', skip 'A'
C: STRB R8, [R0, R11] ; nothing to skip, just fall through to the loop
LOOP: ADDS R11, R11, #1
...
However, note that unlike most architectures, ARM's conditional execution applies to most instructions. Thus an alternative approach, given a small number of simple routines (1-3 instructions) is to actually remove all the branches, and let conditional execution take care of it:
...
LDRB R5, [R0, R11]
CMP R5, R9
STRBEQ R10, [R0, R11]
CMP R5, R8
STRBEQ R7, [R0, R11]
CMP R5, R7
STRBEQ R6, [R0, R11]
CMP R5, R6
STRBEQ R8, [R0, R11]
ADDS R11, R11, #1
...
That way, everything gets "executed", but any stores which fail their condition check just do nothing.