Need help translating following C function to SPARC assembler - c

I was working on a SPARC assembly program in which I call a subroutine called power which takes a base number and multiplies the base times its self based on the exponent. Essentially just calculating a power function. My problem is I am having trouble translating the following C function into SPARC assembly.
power(int base, int exponent)
{
register int p, e;
p = 1;
for(int e=1; e <= exponent; e++)
{
p *= base;
}
}
This is what I have but I just get 49 as my answer:
.global main
main: save %sp,-96,%sp
mov 7,%i0
mov 5,%i1
mov 1,%l2
loop: mov %i0,%o0
mov %i0,%o1
call .mul
nop
cmp %l2,%i1
ble loop
dec %i1

.global main
main: save %sp,-96,%sp
mov 7,%i0 ! base
mov 5,%i1 ! exponent
mov 1,%l2 ! p
mov %l2,%o0 ! %o0 = p = 1
cmp %i1,0
ble end ! if (exponent <= 0) -> end
loop: mov %i0,%o1 ! %o1 = base
call .mul ! %o0 = %o0 * %o1 -> p = p * base
nop
cmp %l2,%i1
bl loop
dec %i1
end:
Changes to get the result (7⁵=16807):
Initalized %o0 with 1
Removed mov %i0,%o0 (every iteration you were smashing the mul result)
Replaced ble by bl

Related

Assembly Power(A,b) function

I'm trying to make an assembly power(a, b) function, based on this c code:
int power(int x, int y)
{
int z;
z = 1;
while (y > 0) {
if ((y % 2) == 1) {
y = y - 1;
z = z * x;
} else {
y = y / 2;
x = x * x;
}
}
return z;
}
Though, for some reason, it only gets some outputs right, and I can't figure out where the problem is. Here is my assembly code:
;* int power(int x, int y); *
;*****************************************************************************
%define y [ebp+12]
%define x [ebp+8]
%define z [ebp-4]
power:
push ebp
mov ebp,esp
sub esp,16
mov byte[ebp-4], 1
jmp L3;
L1:
mov eax,[ebp+12]
and eax,0x1
test eax,eax
je L2;
sub byte[ebp+12],1
mov eax,[ebp-4]
imul eax, [ebp+8]
mov [ebp-4],eax
jmp L3;
L2:
mov eax,[ebp+12]
mov edx,eax
shr edx,31
add eax,edx
sar eax,1
mov [ebp+12],eax
mov eax,[ebp+8]
imul eax,[ebp+8]
mov [ebp+8],eax
L3:
cmp byte[ebp+12],0
jg L1;
mov eax,[ebp-4]
leave
ret
When I run it, this is my output:
power(2, 0) returned -1217218303 - incorrect, should return 1
power(2, 1) returned 2 - correct
power(2, 2) returned -575029244 - incorrect, should return 4
power(2, 3) returned 8 - correct
Could someone please help me figure out where I've gone wrong, or to correct my code, any help would be appreciated.
You're storing a single byte, then reading back that byte + 3 garbage bytes.
%define z [ebp-4] ; what's the point of this define if you write it out explicitly instead of mov eax, z?
; should just be a comment if you don't want use it
mov byte[ebp-4], 1 ; leaves [ebp-3..ebp-1] unmodified
...
mov eax, [ebp-4] ; loads 4 bytes, including whatever garbage was there
Using a debugger would have shown you that you were getting garbage in EAX at this point. You could fix it by using movzx eax, byte [ebp-4], or by storing 4B in the first place.
Or, better, don't use any extra stack memory at all, since you can use ECX without even saving/restoring it in the usual 32-bit calling conventions. Keep your data in registers, that's what they're for.
Your "solution" of using [ebp+16] is writing to stack space owned by the caller. You're just getting lucky that it happens to have the upper 3 bytes zeroed, I guess, and that clobbering it doesn't lead to a crash.
and eax,1
test eax,eax
is redundant: test eax, 1 is sufficient. (Or if you want to destroy eax, and eax, 1 sets flags based on the result).
There's a huge amount of other inefficiency in your code, too.

Hybrid program (.asm + .cpp): modify small math program's code to include float input

(Intel x86. TASM and BorlandC compilers, and TLINK used.)
In main1.cpp the program takes int input (until you input a number smaller than -999999), puts it into an array x[], puts the number of inputs into array's 0th element, sends array's pointer to f1.asm, adds the numbers, and returns the result to main1.cpp so it can be displayed.
How to modify it so it will include floating-point numbers as input?
My specific problems:
The location of the input's offset in f1.asm changes when I turn int into float, and I can't find it ;
Math operations on floats in .asm.
(I couldn't really comprehend explanation on .asm floats I found elsewhere.)
Thank you in advance.
main1.cpp:
#include <iostream.h>
#include <stdlib.h>
#include <math.h>
extern "C" int f1( int* x );
int main()
{
int x[100], i ;
for( i = 1 ; x[i-1]>=-999999 ; i++ )
{
cout << "x[" << i << "] = " ;
cin >> x[i] ; // Input elements while they're >= -999999
}
x[0] = i-1 ; // 0th array element gets the number of inputed elements
cout<<"\nSum of inputs = " << f1(x) ;
return 0;
}
f1.asm:
.model SMALL, C
.data
.code
PUBLIC f1
f1 PROC
push BP
mov BP,SP ; SP contains input from the c++ function
mov ax,[bp+4] ; get the address of the array
mov bp, ax ; BP now points to the array's 0th element
; (which is the the number of the to-be-added c++ inputs)
mov di, 0
mov ax, 0
mov cx, [bp] ; number of unputs gets stored in cx
dec cx
add bp, 2 ; Move bp to point at the next number -- the first c++ input
loop1:
mov bx, [bp]
add ax, bx ; add the input to the growing pile
add bp, 2 ; move the offset to point to the next input
inc di ; increase the Additions Counter
cmp di, cx ; if you add up all of the c++ inputs, exit loop
jne loop1
pop BP
ret
f1 ENDP
.stack
db 100(?)
END
An example as addition to the comments of Ross Ridge.
main.cpp:
#include <iostream.h>
extern "C" {
int f1( int* );
float f2( float* );
}
int main()
{
int x1[100] = {5,3,4,5,6};
float x2[100] = {5,3.0,4.0,5.0,6.5};
cout << "Sum of x1 = " << f1(x1) << endl;
cout << "Sum of x2 = " << f2(x2) << endl;
return 0;
}
f1.asm:
.model SMALL, C
LOCALS ##
PUBLIC f1, f2
.code
f1 PROC
push BP
mov BP,SP ; SP contains input from the c++ function
mov ax,[bp+4] ; get the address of the array
mov bp, ax ; BP now points to the array's 0th element
; (which is the the number of the to-be-added c++ inputs)
mov di, 0
mov ax, 0
mov cx, [bp] ; number of unputs gets stored in cx
dec cx
add bp, 2 ; Move bp to point at the next number -- the first c++ input
##loop1:
mov bx, [bp]
add ax, bx ; add the input to the growing pile
add bp, 2 ; move the offset to point to the next input
inc di ; increase the Additions Counter
cmp di, cx ; if you add up all of the c++ inputs, exit loop
jne ##loop1
pop BP
ret
f1 ENDP
f2 PROC
push bp
mov bp, sp
sub sp, 2 ; Space for a local temporary variable
mov bx,[bp+4] ; Get the address of the array into BX
; (BP is used otherwise)
fld dword ptr ss:[bx] ; Load the first float
fistp word ptr [bp-2] ; and store it as int
mov cx, [bp-2] ; Length of array
dec cx
mov di, 0
fldz ; Load null into ST0
add bx, 4 ; Move bx to point to the next float
##loop1:
fadd dword ptr ss:[bx] ; ST0 = ST0 + [BX]
add bx, 4 ; move the offset to point to the next input
inc di ; increase the Additions Counter
cmp di, cx ; if you add up all of the c++ inputs, exit loop
jne ##loop1
mov sp, bp
pop bp
ret ; Return value in ST0
f2 ENDP
END
Build & run:
PATH <Path to BCC>\BIN;<Path to TASM>\BIN
BCC.EXE main.cpp f1.asm
main.exe

NASM Assembly mathematical logic

I have a program in assembly for the Linux terminal that's supposed to work through a series of mathematical manipulations, compare the final value to 20, and then using if logic, report <, > or = relationship. Code is:
segment .data
out_less db "Z is less than 20.", 10, 0
out_greater db "Z is greater than 20.", 10, 0
out_equal db "Z is equal to 20.", 10, 0
segment .bss
segment .text
global main
extern printf
main:
mov eax, 10
mov ebx, 12
mov ecx, eax
add ecx, ebx ;set c (ecx reserved)
mov eax, 3
mov ebx, ecx
sub ebx, eax ;set f (ebx reserved)
mov eax, 12
mul ecx
add ecx, 10 ;(a+b*c) (ecx reserved)
mov eax, 6
mul ebx
mov eax, 3
sub eax, ebx
mov ebx, eax ;(d-e*f) (ebx reserved) reassign to ebx to free eax
mov eax, ecx
div ebx
add ecx, 1 ;(a+b*c)/(d-e*f) + 1
cmp ecx, 20
jl less
jg greater
je equal
mov eax, 0
ret
less:
push out_less
call printf
jmp end
greater:
push out_greater
call printf
jmp end
equal:
push out_equal
call printf
jmp end
end:
mov eax, 0
ret
Commands for compiling in terminal using nasm and gcc:
nasm -f elf iftest.asm
gcc -o iftest iftest.o
./iftest
Equivalent C code would be:
main() {
int a, b, c, d, e, f, z;
a = 10;
b = 12;
c = a + b;
d = 3;
e = 6;
f = c - d;
z = ((a + b*c) / (d - e*f)) + 1;
if (z < 20) {
printf("Z (%d) is less than 20.\n", z);
}
else if (z > 20) {
printf("Z is greater than 20.\n");
}
else {
printf("Z is equal to 20.\n");
}
}
The current output is incorrect. The C code will report that z = -1, and therefore less than 20, but the assembly code outputs Z is greater than 20. I've tried printing out the final value, but I run into this issue where printing the value somehow changes it. I've checked and rechecked the math logic and I can't see why it shouldn't give the correct value, unless I'm using the math operators incorrectly. Any and all help is appreciated.
I think the problem is here:
div ebx
add ecx, 1 ;(a+b*c)/(d-e*f) + 1
The result of the div instruction is not in ecx.

Convert C program into assembly code

How exactly do I convert this C program into assembly code? I am having a hard time understanding this process or how to even start it. I am new to this. Any help would be appreciated!
while(a!=b){
if(a > b){
a = a - b;
}
else{
b = b - a;
}
}
return a;
}
Side Note: Assume two positive integers a and b are already given in register R0 and R1.
Can you leave comments explaining how you did it?
If you are using gcc, you can get the assembly as gcc -S -o a.s a.c if your source code is a.c. If you are using Visual Studio, you can get it when you debug by selecting the "disassembly" window. Here is the output of Visual studio (I named the subrountine/function called "common" that's why "common" appears):
while(a!=b){
003613DE mov eax,dword ptr [a]
003613E1 cmp eax,dword ptr [b]
003613E4 je common+44h (0361404h)
if(a > b){
003613E6 mov eax,dword ptr [a]
003613E9 cmp eax,dword ptr [b]
003613EC jle common+39h (03613F9h)
a = a - b;
003613EE mov eax,dword ptr [a]
003613F1 sub eax,dword ptr [b]
003613F4 mov dword ptr [a],eax
}
else{
003613F7 jmp common+42h (0361402h)
b = b - a;
003613F9 mov eax,dword ptr [b]
003613FC sub eax,dword ptr [a]
003613FF mov dword ptr [b],eax
}
}
00361402 jmp common+1Eh (03613DEh)
return a;
00361404 mov eax,dword ptr [a]
}
Here variable a is saved in memory initially and so is b (dword ptr [b]).
The professor that taught me system programming used what he called 'atomic-C' as a stepping stone between C and assembly. The rules for atomic-C are (to the best of my recollection):
only simple expressions allowed, i.e. a = b + c; is allowed a = b + c + d; is not allowed because there are two operators there.
only simple boolean expressions are allowed in an if statement, i.e. if (a < b) is allowed but if (( a < b) && (c < d)) is not allowed.
only if statements, no else blocks.
no for / while or do-while is allowed, only goto's and label's
So, the above program would translate into;
label1:
if (a == b)
goto label2;
if (a < b)
goto label4;
a = a - b;
goto label3;
label4:
b = b - a;
label3:
goto label1;
label2:
return a;
I hope I got that correct...it has been almost twenty years since I last had to write atomic-C. Now assuming the above is correct, lets start converting some of the atomic-C statements into MIPS (assuming that is what you are using) assembly. From the link provided by Elliott Frisch, we can almost immediately translate the subtraction steps:
a = a - b becomes R0 = R0 - R1 which is: SUBU R0, R0, R1
b = b - a becomes R1 = R1 - R0 which is: SUBU R1, R1, R0
I used unsigned subtraction due to both a and b being positive integers.
The comparisons can be done thusly:
if(a == b) goto label2 becomes if(R0 == R1) goto label2 which is: beq R0, R1, L2?
The problem here is that the third parameter of the beq op-code is the displacement that the PC moves. We will not know that value till we are done doing the hand assembly here.
The inequality is more work. If we leave of the pseudo code instructions, we first need to use the set on less than op-code which put a one in destination register if the first register is less than the second. Once we have done that, we can use the branch on equal as described above.
if(a < b) becomes slt R2, R0, R1
goto label4 beq R2, 1, L4?
Jumps are simple, they are just j and then the label to jump to. So,
goto label1 becomes j label1
Last thing we have to handle is the return. The return is done by moving the value we want to
a special register V0 and then jumping to the next instruction after the call to this function. The issue is MIPS doesn't have a register to register move command (or if it does I've forgotten it) so we move from a register to RAM and then back again. Finally, we use the special register R31 which holds the return address.
return a becomes var = a which is SW R0, var
ret = var which is LW var, V0
jump RA which is JR R31
With this information, the program becomes. And we can also adjust the jumps that we didn't know before:
L1:
0x0100 BEQ R0, R1, 8
0x0104 SLT R2, R0, R1 ; temp = (a < b) temp = 1 if true, 0 otherwise
0x0108 LUI R3, 0x01 ; load immediate 1 into register R3
0x010C BEQ R2, 1, 2 ; goto label4
0x0110 SUBU R0, R0, R1 ; a = a - b
0x0114 J L3 ; goto label3
L4:
0x0118 SUBU R1, R1, R0 ; b = b - a;
L3:
0x011C J L1 ; goto lable1
L2:
0x0120 SW R0, ret ; move return value from register to a RAM location
0x0123 LW ret, V0 ; move return value from RAM to the return register.
0x0124 JR R31 ; return to caller
It has been almost twenty years since I've had to do stuff like this (now a days, if I need assembly I just do what others have suggested and let the compiler do all the heavy lifting). I am sure that I've made a few errors along the way, and would be happy for any corrects or suggestions. I only went into this long-winded discussion because I interpreted the OP question as doing a hand translation -- something someone might do as they were learning assembly.
cheers.
I've translated that code to 16-bit NASM assembly:
loop:
cmp ax, bx
je .end; if A is not equal to B, then continue executing. Else, exit the loop
jg greater_than; if A is greater than B...
sub ax, bx; ... THEN subtract B from A...
jmp loop; ... and loop back to the beginning!
.greater_than:
sub bx, ax; ... ELSE, subtract A from B...
jmp loop; ... and loop back to the beginning!
.end:
push ax; return A
I used ax in place of r0 and bx in place of r1
ORG 000H // origin
MOV DPTR,#LUT // moves starting address of LUT to DPTR
MOV P1,#00000000B // sets P1 as output port
MOV P0,#00000000B // sets P0 as output port
MAIN: MOV R6,#230D // loads register R6 with 230D
SETB P3.5 // sets P3.5 as input port
MOV TMOD,#01100001B // Sets Timer1 as Mode2 counter & Timer0 as Mode1 timer
MOV TL1,#00000000B // loads TL1 with initial value
MOV TH1,#00000000B // loads TH1 with initial value
SETB TR1 // starts timer(counter) 1
BACK: MOV TH0,#00000000B // loads initial value to TH0
MOV TL0,#00000000B // loads initial value to TL0
SETB TR0 // starts timer 0
HERE: JNB TF0,HERE // checks for Timer 0 roll over
CLR TR0 // stops Timer0
CLR TF0 // clears Timer Flag 0
DJNZ R6,BACK
CLR TR1 // stops Timer(counter)1
CLR TF0 // clears Timer Flag 0
CLR TF1 // clears Timer Flag 1
ACALL DLOOP // Calls subroutine DLOOP for displaying the count
SJMP MAIN // jumps back to the main loop
DLOOP: MOV R5,#252D
BACK1: MOV A,TL1 // loads the current count to the accumulator
MOV B,#4D // loads register B with 4D
MUL AB // Multiplies the TL1 count with 4
MOV B,#100D // loads register B with 100D
DIV AB // isolates first digit of the count
SETB P1.0 // display driver transistor Q1 ON
ACALL DISPLAY // converts 1st digit to 7seg pattern
MOV P0,A // puts the pattern to port 0
ACALL DELAY
ACALL DELAY
MOV A,B
MOV B,#10D
DIV AB // isolates the second digit of the count
CLR P1.0 // display driver transistor Q1 OFF
SETB P1.1 // display driver transistor Q2 ON
ACALL DISPLAY // converts the 2nd digit to 7seg pattern
MOV P0,A
ACALL DELAY
ACALL DELAY
MOV A,B // moves the last digit of the count to accumulator
CLR P1.1 // display driver transistor Q2 OFF
SETB P1.2 // display driver transistor Q3 ON
ACALL DISPLAY // converts 3rd digit to 7seg pattern
MOV P0,A // puts the pattern to port 0
ACALL DELAY // calls 1ms delay
ACALL DELAY
CLR P1.2
DJNZ R5,BACK1 // repeats the subroutine DLOOP 100 times
MOV P0,#11111111B
RET
DELAY: MOV R7,#250D // 1ms delay
DEL1: DJNZ R7,DEL1
RET
DISPLAY: MOVC A,#A+DPTR // gets 7seg digit drive pattern for current value in A
CPL A
RET
LUT: DB 3FH // LUT starts here
DB 06H
DB 5BH
DB 4FH
DB 66H
DB 6DH
DB 7DH
DB 07H
DB 7FH
DB 6FH
END
Although this is compiler's task but if you want to make your hands dirty then look at godbolt
This is great compiler explorer tool let you convert your C/C++ code into the assembly line by line.
If you are a beginner and wants to know "How C program converts into the assembly?" then I have written a detailed post on it here.
http://ctoassembly.com
Try executing your code here. Just copy it inside the main function, define a and b variables before your while loop and you are good to go.
You can see how the code is compiled to assembly with a fair amount of explanation, and then you can execute the assembly code inside a hypothetical CPU.

Translate a FOR to assembler

I need to translate what is commented within the method, to assembler. I have a roughly idea, but can't.
Anyone can help me please? Is for an Intel x32 architecture:
int
secuencia ( int n, EXPRESION * * o )
{
int a, i;
//--- Translate from here ...
for ( i = 0; i < n; i++ ){
a = evaluarExpresion( *o );
o++;
}
return a ;
//--- ... until here.
}
Translated code must be within __asm as:
__asm {
translated code
}
Thank you,
FINAL UPDATE:
This is the final version, working and commented, thanks to all for your help :)
int
secuencia ( int n, EXPRESION * * o )
{
int a = 0, i;
__asm
{
mov dword ptr [i],0 ; int i = 0
jmp salto1
ciclo1:
mov eax,dword ptr [i]
add eax,1 ; increment in 1 the value of i
mov dword ptr [i],eax ; i++
salto1:
mov eax,dword ptr [i]
cmp eax,dword ptr [n] ; Compare i and n
jge final ; If is greater goes to 'final'
mov eax,dword ptr [o]
mov ecx,dword ptr [eax] ; Recover * o (its value)
push ecx ; Make push of * o (At the stack, its value)
call evaluarExpresion ; call evaluarExpresion( * o )
add esp,4 ; Recover memory from the stack (4KB corresponding to the * o pointer)
mov dword ptr [a],eax ; Save the result of evaluarExpresion as the value of a
mov eax,dword ptr [o] ; extract the pointer to o
add eax,4 ; increment the pointer by a factor of 4 (next of the actual pointed by *o)
mov dword ptr [o],eax ; o++
jmp ciclo1 ; repeat
final: ; for's final
mov eax,dword ptr [a] ; return a - it save the return value at the eax registry (by convention this is where the result must be stored)
}
}
Essentially in assembly languages, strictly speaking there isn't a notion of a loop the same way there would be in a higher level language. It's all implemented with jumps (eg. as a "goto"...)
That said, x86 has some instructions with the assumption that you'll be writing "loops", implicitly using the register ECX as a loop counter.
Some examples:
mov ecx, 5 ; ecx = 5
.label:
; Loop body code goes here
; ECX will start out as 5, then 4, then 3, then 1...
loop .label ; if (--ecx) goto .label;
Or:
jecxz .loop_end ; if (!ecx) goto .loop_end;
.loop_start:
; Loop body goes here
loop .loop_start ; if (--ecx) goto .loop_start;
.loop_end:
And, if you don't like this loop instruction thing counting backwards... You can write something like:
xor ecx, ecx ; ecx = 0
.loop_start:
cmp ecx, 5 ; do (ecx-5) discarding result, then set FLAGS
jz .loop_end ; if (ecx-5) was zero (eg. ecx == 5), jump to .loop_end
; Loop body goes here.
inc ecx ; ecx++
jmp .loop_start
.loop_end:
This would be closer to the typical for (int i=0; i<5; ++i) { }
Note that
for (init; cond; advance) {
...
}
is essentially syntactic sugar for
init;
while(cond) {
...
advance;
}
which should be easy enough to translate into assembly language if you've been paying any attention in class.
Use gcc to generate the assembly code
gcc -S -c sample.c
man gcc is your friend
For that you would probably use the loop instruction that decrements the ecx (often called, extended counter) at each loop and goes out when ecx reaches zero.But why use inline asm for it anyway? I'm pretty sure something as simple as that will be optimized correctly by the compiler...
(We say x86 architecture, because it's based on 80x86 computers, but it's an "ok" mistake =p)

Resources