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.
Related
devs! Could you help me? The project's goal is to translate byte code from a fictional architecture, generating an array of real machine code and make it run with jit, but I get a segmentation fault when I try to save a certain part of the output on a file. Part of the code responsible for this:
uint32_t length = sysconf(4096);
void * memory = mmap(0 , length , PROT_NONE , MAP_PRIVATE | MAP_ANONYMOUS , -1 , 0);
//{machine array receives the translated machine code here...}
mprotect ( memory , length , PROT_WRITE ) ;
// copying the machine code array to the memory
memcpy ( memory , ( void *) ( machine ) , sizeof ( machine ) ) ;
mprotect ( memory , length , PROT_EXEC ) ;
uint32_t length = sysconf(4096);
const uint32_t (* jit ) (int32_t*, uint8_t*) = ( uint32_t (*) (int32_t*, uint8_t*) ) ( memory );
// running the machine code to produce de outputs
// &R is the array of registers to store the output and &mem contains the original byte
// code to receive inputs from a instruction that changes the original code
(*jit)((int *)&R, (unsigned char *)&mem);
munmap(memory,length);
// printf/fprintf that causes the segmentation fault if we try to print n and ic[n]
// n = 0; - does not work to print the correct starting value for n
// fflush(stdout); - works to print the correct starting value for n
for(n = 0; n < 16; n++) {
// fprintf(output,"%02x:\n",n);
// fprintf(output,":%d\n",ic[n]);
fprintf(output,"%02x:%d\n",n,ic[n]);
// printf("%02x:%d\n",n,ic[n]);
// fflush(stdout);
}
for (k = 0; k < 16; k++) {
fprintf(output,"R[%d]=0x%08x\n",k,R[k]);
}
The original byte code translated to instructions on this pseudo-assembly code. On this code, the R's represent and array of registers that is passed to the real assembly code R0 is %rdi, R1 = %rdi+0x4,..., R15 = %rdi+0x3C.
Some of those pseudo-instructions translate to one or more actual assembly instructions, and [Rn] represents the memory location which contains the byte code for the original architecture. So when it access [Rn], it uses the current value for the register as the position to get the next 4 bytes (an instruction on the fantasy architecture is 4 bytes long).
mov R0, 0x006C
mov R1, 0x0001
mov R2, [R0]
cmp R15, R2
je 0x0030
mov R14, R2
jg 0x0000
jl 0x0000
add R13, R14
and R12, R13
or R11, R12
xor R10, R11
shl R10, 0x00
shr R10, 0x00
sub R2, R1
mov [R0], R2
jmp 0xFFC8
mov R1, 0x0004
add R0, R1
mov R2, [R0]
add R0, R1
mov R4, [R0]
add R0, R1
mov R8, [R0]
add R0, R1
mov R12, [R0]
jmp 0x0004
mov R3, R12
or R6, R13
add R10, R8
sub R15, R14
For the original architecture instructions (00 to 0F) and 16 registers (R[0] to R[15], the output should follow the model:
original instruction opcode: number of times executed
array of registers: value stored. Something like this:
00:2
01:1
...
0e:1
0f:1
R[0]=0x0000006c
R[1]=0x00000001
...
R[13]=0x03885533
R[14]=0x03885533
R[15]=0x00000000
The problem is that I keep getting a segmentation fault when I try to save the opcode: number of executions. If I try to print only the "opcode:" and register:value pairs, there's no segmentation fault, but instead of printing the first opcode value as "0:", it prints "6C:" which is the R[0] and the r12 (asm register) according to the gdb:
I have tried to insert the push rbp, mov rbp, rsp before the assembly code and the pop rbp, ret after the assembly, but nothing works. Any ideas that could help? Any more infos that I could provide?
Thanks for the help and have a good day.
This question already has an answer here:
Problems with IDIV Assembly Language
(1 answer)
Closed 1 year ago.
The pseudocode is the following:
read c //a double digit number
for(i=1,n,i++)
{ if (n%i==0)
print i;}
In assembly I have written it as:
mov bx,ax ; ax was the number ex.0020, storing a copy in bx.
mov cx,1 ; the start of the for loop
.forloop:
mov ax,bx ; resetting ax to be the number(needed for the next iterations)
div cx
cmp ah,0 ; checking if the remainder is 0
jne .ifinstr
add cl 48 ;adding so my number would be displayed later as decimal
mov dl,cl ;printing the remainder
mov ah,2
int 21h
sub cl,48 ;converting it back to hexa
.ifinstr:
inc cx ;the loop goes on
cmp cx,bx
jle .forloop
I've checked by tracing its steps. The first iteration goes well, then, at the second one, it makes ax=the initial number and cx=2 as it should, but at 'div cx' it jumps somwhere unknown to me and it doesn't stop anywhere. It does:
push ax
mov al,12
nop
push 9
.
.
Any idea why it does that?
try to do mov dx,0 just before div instruction.
Basically every time you come after jump, there may be some data in dx register, so you can just move zero in dx or XOR dx,dx.
This is to be done, because otherwise division will be considered differently.
See this:
Unsigned divide.
Algorithm:
when operand is a byte:
AL = AX / operand
AH = remainder (modulus)
when operand is a word:
AX = (DX AX) / operand
DX = remainder (modulus)
Example:
MOV AX, 203 ; AX = 00CBh
MOV BL, 4
DIV BL ; AL = 50 (32h), AH = 3
RET
I have a problem which is bugging me for multiple days now...
I call a function from c which is implemented in arm assembler on a raspberry pi using the neon module. The signature looks like the following:
void doStuff(const uint32_t key[4])
I can load all the values into d-registers using VLD4.32 {d6-d9}, [r0].
The problem is that I have to use a value at a certain index of the array which is calculated at runtime. So I have to access the array at an index which I only know at runtime.
In c, the code I want to achieve would look like this:
// calculations
int i = ... // 'i' is the index of value in the array
int result = key[i];
In assembler I tried this:
VMOV r8, s22 ;# copy the calculated index into an arm register
MOV r8, r8, LSL #0x2;# multiply with 4
ADD r8, r5, r8 ;# add offset to base adress
VLDR.32 d14, [r8] ;# load from adress into d-register
I also tried multiplying with 2 and 32 instead of 4. But I always get the value 3.
I got it working with this stupid and very slow solution:
;# <--- very slow and ugly --->
VLD4.32 {d6-d9}, [r1] ;# load 4x32bit from adress *r1
VMOV r6, s22 ;# r6 now contains the offset which is either 0,1,2 or 3
CMP r6, #0x0 ;# 3 - 0 == 0 -> Z set
BEQ equal0
CMP r6, #0x1
BEQ equal1
CMP r6, #0x2
BEQ equal2
VMOV d12, d9 ;# has to be 3
B continue
equal0:
VMOV d12, d6
B continue
equal1:
VMOV d12, d7
B continue
equal2:
VMOV d12, d8
B continue
continue:
;# <--- --->
I basically have an if for every possible number and then select the corresponding register.
Thanks!
Edit:
Okay it works with VLD1.32 d14, [r8]. Do not quite unterstand why it won't work with VLDR.32, though.
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
I'm currently learning assembly x86 and I have made a little task for myself.
The C code:
if (a == 4711) { a = a + 2 } else
{ a = a - 2 }
Assembler Code (eax is a register, cmp is compare, jne is jump if not equal and jmp is jump if equal):
mov eax, a
cmp eax, 4711
jmp equal
equal: add eax, 2
jne unequal
unequal: sub eax, 2
I think a little more efficient than that would be:
mov eax, a
cmp eax, 4711
jne unequal
add eax, 2
unequal: sub eax, 2
Edit:
mov eax, a
cmp eax, 4711
jne unequal
equal: add eax, 2
jmp continue
unequal: sub eax, 2
continue: ...
Did I translate it correctly?
Nope.
In the first case, your jne unequal does nothing since control would go there anyway. You need to jump to after that.
In your second case, if the comparison is true, you both add and subtract 2, doing nothing.
You also don't store the result back where the original value was, you just leave it in eax.
Your edit is correct except for one thing.
mov eax, a
moves the address of "a" into eax, not the contents/value
This short snippet is done with NASM on Ubuntu 16.04 elf64
section .text
global _start
_start
mov eax, a
cmp eax, 4711
jnz unequal
add eax, 2
jmp Done
unequal:
sub eax, 2
Done: mov [a], eax
section .rodata
a dd 180308
It disassembles to;
00400080 B89C004000 mov eax,0x40009c
00400085 3D67120000 cmp eax,0x1267
0040008A 7505 jnz 0x400091
0040008C 83C002 add eax,byte +0x2
0040008F EB03 jmp short 0x400094
00400091 83E802 sub eax,byte +0x2
00400094 8904259C004000 mov [0x40009c],eax
Variable "a" lives here
0040009C 54C00200
Note that # 4000080 the address of a is moved into EAX, but # Done (400091), whatever is in EAX is moved into that address. Notice too, the value # "a" is stored in reverse order (little endian. Usually in code you'd see it as 0x2c054
Let's get back to your first code:
mov eax, a
cmp eax, 4711
jmp equal
equal: add eax, 2
jne unequal
unequal: sub eax, 2
Let's pretend the first instruction load eax with "a" (it actually would in TASM/MASM, but rather stick to explicit and accurate [a], it's easier to read the source and works also in NASM).
Second instruction is cmp, which does subtract 4711 from eax, throws the result away (not storing it anywhere), and only flag register is affected. If "a" was 4711, then result of subtraction is zero, so ZF=1 then. Otherwise ZF=0. (for other flags affected by CMP see some documentation).
So on line 3 the eax still contains value from "a", and flag register contains result of cmp eax,4711. And you do jmp. This is unconditional jump, happening no matter what, so you directly continue to instruction at "equal" address, which is add eax,2. => You add 2 to "a" in every case.
Also the add itself affects flags, so for "a" == -2 the ZF=1, otherwise ZF=0!
Then comes the first conditional jump, branching the code, based on current flag register content. The jne is abbreviation of "jump not equal", and "equal" in this context means set zero flag (ZF=1).
So when "a" was -2, ZF is 1 ("is equal") ahead of jne, thus jne will NOT jump to the "unequal" address, but will continue to the next instruction (which is actually at "unequal" address anyway, so the jne is meaningless).
For "a" different from -2 the ZF will be 0 ("is not equal"), so jne will execute the jump on the provided label, continuing with instruction at address "unequal".
So you have to navigate the CPU away from instructions you don't want to execute.
xor eax,eax ; sets eax to 0, and ZF=1
jz label_1 ; ZF is 1, so jump is executed, CPU goes to "label_1"
inc eax ; this instruction is then skipped and not executed
label_1:
; eax being still 0, and ZF being still set ON
; whatever instruction is here, CPU will execute it after the "jz"
Slightly modified example to show the case when condition is false
xor eax,eax ; sets eax to 0, and CF=0, ZF=1, ...
jc label_1 ; CF is 0, so "jump carry" is NOT executed
inc eax ; this instruction is executed after "jc"
label_1:
; here eax is 1
; CF is still 0 (not affected by INC)
; but ZF is 0 (affected by INC)
Summary: you should have pretty good idea what instructions affect what flags, and in what way. When unsure, keep CMP + Jcc pair together (to not affect flag results from cmp accidentally). Jcc stands for any "conditional jump" instruction. When the condition is met, the jump to provided label is executed. Otherwise the Jcc instruction is ignored, and execution does continue with instruction right after it.
BTW, I personally would write that C code:
if (a == 4711) { a = a + 2 } else
{ a = a - 2 }
as:
cmp [a],DWORD 4711
mov eax,2
je a_is_4711
neg eax ; -2 for non 4711 value
a_is_4711:
add [a],eax