I am trying to write a function that converts decimal numbers into binary in assembler. Since printing is so troublesome in there, I have decided to make a separate function in C that just prints the numbers. But when I run the code, it always prints '0110101110110100'
Heres the C function (both print and conversion):
void printBin(int x) {
printf("%d", x);
}
void DecToBin(int n)
{
// Size of an integer is assumed to be 16 bits
for (int i = 15; i >= 0; i--) {
int k = n >> i;
printBin(k & 1);
}
heres the code in asm:
.globl _DecToBin
.extern _printBin
_DecToBin:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp),%eax
movl $15, %ebx
cmpl $0, %ebx
jl end
start:
movl %ebx, %ecx
movl %eax, %edx
shrl %cl, %eax
andl $1, %eax
pushl %eax
call _printBin
movl %edx, %eax
dec %ebx
cmpl $0, %ebx
jge start
end:
movl %ebp, %esp
popl %ebp
ret
Cant figure out where the mistake is. Any help would be appreciated
disassembled code using online program
Your principle problem is that it is very unlikely that %edx is preserved across the function call to printBin.
Also:
%ebx is not a volatile register in most (any?) C calling convention rules. You need to check your compilers documentation and conform to it.
If you are going to use ebx, you need to save and restore it.
The stack pointer needs to be kept aligned to 16 bytes. On my machine (macos), it SEGVs under printBin if you don’t.
Related
So I've been working on a problem (and before you ask, yes, it is homework, but I've been putting in faithful effort!) where I have some assembly code and want to be able to convert it (as faithfully as possible) to C.
Here is the assembly code:
A1:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $0, -4(%ebp)
jmp .L2
.L4:
movl -4(%ebp), %eax
sall $2, %eax
addl 8(%ebp), %eax
movl (%eax), %eax
cmpl 12(%ebp), %eax
jg .L6
.L2:
movl -4(%ebp), %eax
cmpl 16(%ebp), %eax
jl .L4
jmp .L3
.L6:
nop
.L3:
movl -4(%ebp), %eax
leave
ret
And here's some of the C code I wrote to mimic it:
int A1(int a, int b, int c) {
int local = 0;
while(local < c) {
if(b > (int*)((local << 2) + a)) {
return local;
}
}
return local;
}
I have a few questions about how assembly works.
First, I notice that in L4, the body of the while loop, nothing is ever assigned to local. It's initialized to be 0 at the start of the function, and then never modified again. Looking at the C code I made for it, though, that seems odd, considering that the loop will go on indefinitely if the if-condition fails. Am I missing something there? I was under the impression that you'd need a snippet of code like:
movl %eax, -4(%ebp)
in order to actually assign anything to the local variable, and I don't see anything like that in the body of the while loop.
Secondly, you'll see that in the assembly code, the only local variable that's declared is "local". Hence, I have to use a snippet of code like:
if(b > (int*)((local << 2) + a))
The output of this line doesn't look much like the assembly code, though, and I think I might have made a mistake. What did I do wrong here?
And finally (thanks for your patience!), on a related note, I understand that the purpose of this if-loop in the while loop is to break out if the condition is fulfilled, and then to return local. Hence L6 and "nop" (which is basically saying nothing). However, I don't know how to replicate this in my program. I've tried "break", and I've tried returning local as you see here. I understand the functionality - I just don't know how to replicate it in C (short of using goto, but that kind of defeats the purpose of the exercise...).
Thank you for your time!
This is my guess:
int A1 (int *a, int value, int size)
{
int i = 0;
while (i<size)
{
if (a[i] <= value)
break;
}
return i;
}
Which, compiled back to assembly, gives me this code:
A1:
.LFB0:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $0, -4(%ebp)
jmp .L2
.L4:
movl -4(%ebp), %eax
leal 0(,%eax,4), %edx
movl 8(%ebp), %eax
addl %edx, %eax
movl (%eax), %eax
cmpl 12(%ebp), %eax
jg .L2
jmp .L3
.L2:
movl -4(%ebp), %eax
cmpl 16(%ebp), %eax
jl .L4
.L3:
movl -4(%ebp), %eax
leave
ret
Now this seems to be identical to your original ASM code, just the code starting at L4 is not the same, but if we anotate both codes:
ORIGINAL
movl -4(%ebp), %eax ;EAX = local
sall $2, %eax ;EAX = EAX*4
addl 8(%ebp), %eax ;EAX = EAX+a, hence EAX=a+local*4
ASM-C-ASM
movl -4(%ebp), %eax ;EAX = i
leal 0(,%eax,4), %edx ;EDX = EAX*4
movl 8(%ebp), %eax ;EAX = a
addl %edx, %eax ;EAX = EAX+EDX, hence EAX=a+i*4
Both codes continue with
movl (%eax), %eax
Because of this, I guess a is actually a pointer to some variable type that uses 4 bytes. By the comparison between the second argument and the value read from memory, I guess that type must be either int or long. I choose int solely by convenience.
Of course this also means that this code (and the original one) does not make any sense. It lacks the i++ part somewhere. If this is so, then a is an array, and the third argument is the size of the array. I've named my local variable i to keep with the tradition of naming index variables like this.
This code would scan the array searching for a value inside it that is equal or less than value. If it finds it, the index to that value is returned. If not, the size of the array is returned.
I'm reviewing a practice midterm at the moment. the question gives a piece of assembly code (IA32) and instructs to write the C equivalent of it. Just want to make sure I'm doing it correctly. Thanks!
Assembly program given:
.global _someOperation
_someOperation:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %ebx
movl 12(%ebp), %edx
decl %edx
xorl %esi, %esi
movl (%ebx, %esi, 4), %eax
continue:
incl %esi
cmpl (%ebx, %esi, 4), %eax
jl thelabel
movl (%ebx, %esi, 4), %eax
thelabel:
cmp %esi, %edx
jne continue
movl %ebp, %esp
popl %ebp
ret
This is the code I've written:
void someOperation(int *num, int count) //Given
{
int k; //Given
count--;
int i = 0;
k = num[i];
i++;
while(count != i)
{
if(k >= num[i]
k = num[i];
i++;
}
return (k);
}
Looks pretty close to me, although in the ASM the increment is only at the beginning of the loop, and the condition is not checked the first time through. Consider using DO...WHILE instead.
EDIT: also, your assignment is wrong. MOV instruction copies from the 2nd parameter to the first. You have it going the other way in your C code.
I have this IA32 assembly language code I'm trying to convert into regular C code.
.globl fn
.type fn, #function
fn:
pushl %ebp #setup
movl $1, %eax #setup 1 is in A
movl %esp, %ebp #setup
movl 8(%ebp), %edx # pointer X is in D
cmpl $1, %edx # (*x > 1)
jle .L4
.L5:
imull %edx, %eax
subl $1, %edx
cmpl $1, %edx
jne .L5
.L4:
popl %ebp
ret
The trouble I'm having is deciding what type of comparison is going on. I don't get how the program gets to the L5 cache. L5 seems to be a loop since there's a comparison within it. I'm also unsure of what is being returned because it seems like most of the work is done is the %edx register, but doesn't go back to %eax for returning.
What I have so far:
int fn(int x)
{
}
It looks to me like it's computing a factorial. Ignoring the stack frame manipulation and such, we're left with:
movl $1, %eax #setup 1 is in A
Puts 1 into eax.
movl 8(%ebp), %edx # pointer X is in D
Retrieves a parameter into edx
imull %edx, %eax
Multiplies eax by edx, putting the result into eax.
subl $1, %edx
cmpl $1, %edx
jne .L5
Decrements edx and repeats if edx != 1.
In other words, this is roughly equivalent to:
unsigned fact(unsigned input) {
unsigned retval = 1;
for ( ; input != 1; --input)
retval *= input;
return retval;
}
I have a rather simple assemble code, but it is making me second guess myself.
fn:
pushl %ebp
movl %esp, %ebp
movl 12(%ebp), %eax
sall $2, %eax
addl 8(%ebp), %eax
movl (%eax), %eax
popl %ebp
ret
So what I have as a function is
int main(int x, int y)
{
x = 4*y + x;
return x;
}
but I thought this looks similar to an array index (saw a similar post but still not sure).
I'm not completely sure if this block of code is correct.
I'm trying to understand the assembly code of the C function. I could not understand why andl -16 is done at the main. Is it for allocating space for the local variables. If so why subl 32 is done for main.
I could not understand the disassembly of the func1. As read the stack grows from higher order address to low order address for 8086 processors. So here why is the access on positive side of the ebp(for parameters offset) and why not in the negative side of ebp. The local variables inside the func1 is 3 + return address + saved registers - So it has to be 20, but why is it 24? (subl $24,esp)
#include<stdio.h>
int add(int a, int b){
int res = 0;
res = a + b;
return res;
}
int func1(int a){
int s1,s2,s3;
s1 = add(a,a);
s2 = add(s1,a);
s3 = add(s1,s2);
return s3;
}
int main(){
int a,b;
a = 1;b = 2;
b = func1(a);
printf("\n a : %d b : %d \n",a,b);
return 0;
}
assembly code :
.file "sample.c"
.text
.globl add
.type add, #function
add:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $0, -4(%ebp)
movl 12(%ebp), %eax
movl 8(%ebp), %edx
leal (%edx,%eax), %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
leave
ret
.size add, .-add
.globl func1
.type func1, #function
func1:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl 8(%ebp), %eax
movl %eax, 4(%esp)
movl 8(%ebp), %eax
movl %eax, (%esp)
call add
movl %eax, -4(%ebp)
movl 8(%ebp), %eax
movl %eax, 4(%esp)
movl -4(%ebp), %eax
movl %eax, (%esp)
call add
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
movl %eax, 4(%esp)
movl -4(%ebp), %eax
movl %eax, (%esp)
call add
movl %eax, -12(%ebp)
movl -12(%ebp), %eax
leave
ret
.size func1, .-func1
.section .rodata
.LC0:
.string "\n a : %d b : %d \n"
.text
.globl main
.type main, #function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $1, 28(%esp)
movl $2, 24(%esp)
movl 28(%esp), %eax
movl %eax, (%esp)
call func1
movl %eax, 24(%esp)
movl $.LC0, %eax
movl 24(%esp), %edx
movl %edx, 8(%esp)
movl 28(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
.section .note.GNU-stack,"",#progbits
The andl $-16, %esp aligns the stack pointer to a multiple of 16 bytes, by clearing the low four bits.
The only places where positive offsets are used with (%ebp) are parameter accesses.
You did not state what your target platform is or what switches you used to compile with. The assembly code shows some Ubuntu identifier has been inserted, but I am not familiar with the ABI it uses, beyond that it is probably similar to ABIs generally used with the Intel x86 architecture. So I am going to guess that the ABI requires 8-byte alignment at routine calls, and so the compiler makes the stack frame of func1 24 bytes instead of 20 so that 8-byte alignment is maintained.
I will further guess that the compiler aligned the stack to 16 bytes at the start of main as a sort of “preference” in the compiler, in case it uses SSE instructions that prefer 16-byte alignment, or other operations that prefer 16-byte alignment.
So, we have:
In main, the andl $-16, %esp aligns the stack to a multiple of 16 bytes as a compiler preference. Inside main, 28(%esp) and 24(%esp) refer to temporary values the compiler saves on the stack, while 8(%esp), 4(%esp), and (%esp) are used to pass parameters to func1 and printf. We see from the fact that the assembly code calls printf but it is commented out in your code that you have pasted C source code that is different from the C source code used to generate the assembly code: This is not the correct assembly code generated from the C source code.
In func1, 24 bytes are allocated on the stack instead of 20 to maintain 8-byte alignment. Inside func1, parameters are accessed through 8(%ebp) and 4(%ebp). Locations from -12(%ebp) to -4(%ebp) are used to hold values of your variables. 4(%esp) and (%esp) are used to pass parameters to add.
Here is the stack frame of func1:
- 4(%ebp) = 20(%esp): s1.
- 8(%ebp) = 16(%esp): s2.
-12(%ebp) = 12(%esp): s3.
-16(%ebp) = 8(%esp): Unused padding.
-20(%ebp) = 4(%esp): Passes second parameter of add.
-24(%ebp) = 0(%esp): Passes first parameter of add.
I would suggest working through this with the output of objdump -S which will give you interlisting with the C source.