I have to write a function in assembly to complete the following c code.
int main(){
int hist[26]={0};
int i;
charHistogram("This is a string", hist);
for (i=0; i<26; i++ )
printf("%c:%d ", i+’a’, hist[i] );
printf("\n");
}
return 0;
}
And this is the assembly code I wrote:
_charHistogram:
push %ebp
movl %esp,%ebp
subl $0x10,%esp
movl $0x0,-0x4(%ebp)
movl $0x41,-0x8(%ebp)
condFor1:
movl -0x4(%ebp),%edx
movl 0X8(%ebp),%eax
cmp (%eax,%edx,1), $0
je exit
condFor2:
cmpl $0x5a,-0x8(%ebp)
jg condFor1
if1:
movl -0x8(%ebp), %ecx
cmp (%eax,%edx,1), %ecx
jne if2
subl $0x41,%ecx
movl 0xc(%ebp), %ebx
add $0x1, (%ebx,%ecx,4)
add 0x20,%ecx
inc %ecx
inc %edx
jmp condFor1
if2:
add 0x20,%ecx
cmp (%eax,%edx,2), %ecx
jne condFor1
subl $0x41,ecx
movl 0xc(%ebp), %ebx
add $0x1, (%ebx,%ecx,4)
add 0x20,%ecx
inc %ecx
inc %edx
jmp condFor1
exit:
leave
ret
Basically the function written in assembly has to count the number of occurences of a letter on a given string and store it at the int array hist. So I thought it could compare each char value to its ascii value starting at 65 to 90 and from 97 to 122. But when I begin to compile the assembly it keeps getting the error "operand size mismatch for 'cmp'" for the instruction cmp (%eax,%edx,1), $0.
Can you help me out?
cmp (%eax,%edx,1), $0
You need to reverse the operands.
cmp $0, (%eax,%edx,1)
Did you notice that you have programmed endless loops?
You setup a variable with movl $0x0,-0x4(%ebp) but you are forgetting to change its value throughout the code!
Since your input string is ASCIIZ shouldn't you compare with CL in stead of comparing with ECX?
Related
The goal of this function is to replicate the strupr C function. It's stuck in an infinite iteration and I cannot figure out why, it doesn't seem to end. The way I'm looking at it is the argv from the command line is sent as a single array of chars, I simply try to access it and determine if it has to be changed and then printed - or simply just printed. It receives a single parameter which is that very same argv value.
void lowerToUpper (char *msg);
.globl lowerToUpper
.type lowerToUpper, #function
lowerToUpper:
mov $0,%r12
lea (%rdi), %rdx
jmp .restartLoop
.restartLoop:
add $8, %rdx
cmp $0,%r13
jne .isValid
ret
.isValid:
cmp $97, %r13
jbe .printValue
jg .changeValue
.changeValue:
#sub $32, %r13
jmp .printValue
.printValue:
mov $format2, %edi
mov %r13, %rsi
mov $0, %eax
call printf
add $1,%rdx
jmp .restartLoop
The goal of this function is to print the highest number in an array. It receives a pointer to an unsigned int (an array of numbers) and it's length.
void printHigher (unsigned int *data, int len);
printHigher:
mov $0,%r14
mov $0,%r15
jmp .Loop
ret
.Loop:
mov (%rdi), %r8
cmp %r8,%rdi
jl .calculateMax
jmp .printMax
.calculateMax:
cmp %r8, %r15
jg .assignMax
add $1,%r14
add $8,(%rdi)
jmp .Loop
.assignMax:
mov %r8, %r15
.printMax:
mov $format, %edi
mov %r15, %rsi
mov $0, %eax
call printf
I'm implementing a simple assembly function called through a program in c, to count how many 1 there are in the odd position of an array in 32 bits. The first argument passed to the function is the pointer to the array while the second the number of elements. I do not understand what it does go to infinite loop.
// Assembly code
.globl ones_in_odds
.type ones_in_odds,#function
ones_in_odds:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%ecx
movl 12(%ebp),%esi
#xorl %edi,%edi
xorl %eax,%eax
subl $-1,%esi
startloop:
cmpl $0,%esi
jl endloop
movl (%ecx,%esi,4),%edx
xorl %edi,%edi
innerloop:
cmpl $16,%edi
jg startloop
shrl %edx
shrl %edx
adcl $00,%eax
incl %edi
jmp innerloop
decl %esi
jmp startloop
endloop:
movl %ebp,%esp
popl %ebp
ret
// C Code
#include <stdio.h>
#define DIM 5
int ones_in_odds(int *,size_t);
int main(){
int array[DIM] = {1,3,4,5,6};
int one = ones_in_odds(array,DIM);
printf("Il numero di 1 nelle posizioni dispari e' %d\n",one);
return 0;
}
This adds 1 to ESI:
subl $-1,%esi
It's like the term ESI = ESI - (-1). You want to transform the count of items (DIM) to the index of the last item in array. Thus the count has to be subtracted by 1 or added by (-1). However, you don't need this transformation at this place. Remove the line.
Because of
jg startloop
you don't reach decl %esi and therefore the break condition jl endloop will never been met.
Move decl %esi to the beginning of startloop and you solve also the transformation problem above.
As #Jester mentions, you have to follow the C calling convention since the assembly procedure is a function of the C program. The function is allowed to change EAX, ECX, and EDX ("caller saved") and has to return all other registers unchanged ("callee saved"). The function changes ESI and EDI, but should returm them unchanged. So push them at the beginning of the function and pop them at the end.
I am new to assembly and I am trying to understand the tools at my disposal as well. I have to create a callable assembly function for a tiny C program. The goal is for the user to type in the letter by hex value -so 41 for A. Then the C passes this hex value as an unsigned char to the assembly function. Below is the C code
extern char *printbin(unsigned char);
int main(void)
{
unsigned int x;
printf("enter the character's ascii value in hex: \n");
scanf("%x",&x);
printf("The binary format for character %c is %s\n",
x, printbin((unsigned char)x));
return 0;
}
My understanding that on the stack there should be a value of 41 stored in one byte as in C chars are really just numbers as well. Is that assumption correct. The task is to covert the input into an ouput string of two 4 digit binary numbers for each digit separated by a space so 0100 0001 My first question is how can I split up the byte in a register to just 4 bits or just the 1 or the 4? I set up a skeleton for the assembly file
.text
.globl _printbin
_printbin:
pushl %ebp
movl %esp, %ebp
movl 4(%ebp), %ecx #store the char in ecx register
jmp end
donibble: #function to convert digit to binary
end:
movl %ebp, %esp
popl %ebp
ret
However I am lost on how to proceed with grabbing just half of the byte. I could grab just the one byte with %el to make it just 8 bits instead of the %ecx when I do "work" on it but I am unaware of any kind of register to grab anything fewer then just 1 byte. Any help or ideas would be greatly appreciated.
Updated assembly code
.text
.globl _printbin
_printbin:
pushl %ebp
movl %esp, %ebp
movl 4(%ebp), %edx #grabs the hex byte
movl $0, %eax #sets $eax to 0
shrb $4,%dl
jmp donibble
L2:
incl %eax
# addl 0x20, %return string #add the space.
movl 4(%ebp), %edx
AND %dl, 0x0f
jmp donibble
L3:
jmp end
donibble:
#Takes %dl and gets string and adds string to return String
cmpb %dl, 0x0
je Zero
cmpb %dl, 0x1
je One
Zero:
#add 0000 to string
jmp donibbleEnd
One:
#add 0001 to string
donibbleEnd:
#to send back to printbin
cmpb $0, %eax
je L2
jmp L3
end:
movl $returnString, %eax
movl %ebp, %esp
popl %ebp
ret
.data
returnString:
.asciz "1001 1100\n"
.end
Is there a way to add to my $returnString following this updated structure above? apparently addl "0000", $returnString doesn't work at all :)
That's a weird prototype for the function. Are you supposed to return a pointer to a static buffer? A more typical design would be for the caller to pass a pointer to a buffer where the function could store the string.
The usual way to do this is to take advantage of the fact that the shift instructions set CF to the last bit shifted out. You can then use setc to get a zero or one, and convert that to an ascii '0' or '1'. Another trick is adc $0, or adc $'0' to read the carry flag.
copying a register and using and to get just the low bit is also viable, though.
If you're stuck, use the search. There have been previous SO questions about this. Try searching within the x86 and/or assembly tags. Have a look at the x86 tag wiki for many good links to beginner stuff and reference material.
For the record to close this out. This was the code I ended with. I appreciate the help from everyone.
.text
.globl _printbin
_printbin:
pushl %ebp
movl %esp, %ebp
movb 8(%ebp), %dl #grabs the hex byte
movl $0, %eax #sets $eax to 0
shrb $4, %dl
movl $returnString, %ecx
pushl %ebx #free up ebx
jmp donibble
returnFromDonibble:
incl %ecx
movb 8(%ebp), %dl
movb $0x0f, %al
andb $15, %dl
movb $0x39, %al
cmpb (%ecx), %al
je donibble
jne end
donibble:
#Takes %dl and gets string and adds string to return String
movb %dl, %bl
movb $0x08, %al
andb $8,%dl
je zero
jne one
one:
movb $0x31, (%ecx)
incl %ecx
jmp L2
zero:
movb $0x30, (%ecx)
incl %ecx
jmp L2
L2:
movb %bl, %dl
movb $0x04, %al
andb $4, %dl
je zero2
jne one2
one2:
movb $0x31, (%ecx)
incl %ecx
jmp L3
zero2:
movb $0x30, (%ecx)
incl %ecx
jmp L3
L3:
movb %bl, %dl
movb $0x02, %al
andb $2, %dl
je zero3
jne one3
one3:
movb $0x31, (%ecx)
incl %ecx
jmp L4
zero3:
movb $0x30, (%ecx)
incl %ecx
jmp L4
L4:
movb %bl, %dl
movb $0x01, %al
andb $1, %dl
je zero4
jne one4
one4:
movb $0x31, (%ecx)
incl %ecx
jmp returnFromDonibble
zero4:
movb $0x30, (%ecx)
inc %ecx
jmp returnFromDonibble
end:
popl %ebx
movl $returnString, %eax
movl %ebp, %esp
popl %ebp
ret
.data
returnString: .asciz "9999 9999"
.end
Hi I have a function in C that returns the max of a set of numbers in an array. I need to convert it into assembly and make it callable from C. nums is the array in which all the numbers are stored. len is the length of the array that was passed. The other variables that I made are local variables
.global max
.text
.equ word_size, 4
max:
#prologue
push %ebp
movl %esp, %ebp
.equ nums, 2*word_size
.equ len, 3*word_size
.equ cur_max, 4*word_size
.equ index, 5*word_size
#eax is index
#short cur_max = nums[0]
movl cur_max(%ebp), %eax
movl $0, %ebx
mov nums(%ebp), %edx
leal (%edx, %ebx, word_size), %edx
mov %edx, cur_max(%ebp)
#for(index = 1; index < len;index++)
mov index(%ebp), %eax
mov len(%ebp), %ebx
mov nums(%ebp), %ecx
mov cur_max(%ebp), %edx
mov $1, %eax
for_loop_begin:
cmp %ebx, %eax
jl loop_begin
jmp for_loop_end
loop_begin:
if_loop:
leal (%ecx,%eax,word_size), %esi #nums[i] = esi
cmp %edx,%esi
jg in_if_loop
in_if_loop_end:
inc %eax
jmp for_loop_begin
for_loop_end:
mov %edx,%eax
ret
in_if_loop:
mov %esi,%edx
movl %ebp, %esp
pop %ebp
jmp in_if_loop_end
This is the C code
short max(short* nums, int len){
int index;
short cur_max = nums[0];
for( index = 1; index < len; index++)
if( nums[index] > cur_max)
cur_max = nums[index];
return cur_max;
}
I'm having so much difficulty with a question I was assigned for homework. I have the following C code and the subsequent assembly:
int foo(int n, int A[X(n)][Y(n)], int j){
int i;
int result = 0;
for (i = 0; i < X(n); i++)
result += A[i][j];
return result;
}
movl 8(%ebp), %eax
leal (%eax,%eax), %edx
leal (%edx,%eax), %ecx
movl %edx, %ebx
leal 1(%edx), %eax
movl $0, %edx
testl %eax, %eax
jle .L3
leal 0(,%ecx,4), %esi
movl 16(%ebp), %edx
movl 12(%ebp), %ecx
leal (%ecx,%edx,4), %eax
movl $0, %edx
movl $1, %ecx
addl $2, %ebx
.L4:
addl (%eax), %edx
addl $1, %ecx
addl %esi, %eax
cmpl %ebx, %ecx
jne .L4
.L3:
movl %edx, %eax
I need to find out the definitions of X and Y. I believe that n is initially stored in eax, and then 2n is stored in edx and 3n in ecx. So I think esi would equal 3n * 4. Also, because result is initially stored as movl $0, %edx and the following lines are incremented by one I'm thinking that X would be equal to #define X(n + 1). Also, I believe addl %esi, %eax would be Y. So since esi = %ecx * 4 does Y = 4n? However, this is where I begin to get severely confused. Thank's all.
Cute exercise.
The declaration seems to define A as a C99 variable-length-array. Incidentally these have exceedingly poor compiler support and are optional in C11.
The inner Y(n) dimension may then be inferred from the array stride across loop iterations, where EAX is the pointer and ESI the pitch, and appears to be defined as n*3. As for X(n) we may infer it from the loop entry condition when i = 0, and it appears to expand as N*2+1.
#define X(n) ((n)*2+1)
#define Y(n) ((n)*3)
Annotated assembly:
_foo:
;Prologue (assumed)
push ebp
mov ebp,esp
;Pre-scale N
mov eax,[ebp+8]
lea edx,[eax+eax]
lea ecx,[edx+eax] ;ECX = N*3
mov ebx,edx ;EBX = N*2
;Bail out earily if X(n) <= 0
lea eax,[edx+1] ;EAX = N*2+1
mov edx,0
test eax,eax ;(OF=0)
jle ##end ;Proceed if N*2+1 > 0
;Prepare loop counters
lea esi,[ecx*4] ;ESI = N*3*sizeof int, array stride
mov edx,[ebp+16] ;EDX = j
mov ecx,[ebp+12]
lea eax,[ecx+edx*4] ;EAX = &A[0][j]
mov edx,0 ;EDX = 0, accumulator
mov ecx,1 ;ECX = 1, loop counter
add ebx,2 ;EBX = N*2+2
;Step through the loop
##loop:
add edx,[eax] ;EDX += A[i][j]
add ecx,1 ;Increment loop counter
add eax,esi ;++A
cmp ecx,ebx
jne ##loop ;[1..N*2+2) <=> [0..N*2+1)
##end:
;Epilogue
mov eax,edx ;Return the sum
pop ebp
ret