Gas Assembly x86. converting char to binary string - c

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

Related

Update array in assembly

Just starting to learn assembly, so I am having trouble with some basic. For example, I am trying to modify a file that normally runs to find the maximum value.
What I am trying to do is iterate through the data_items and modify it by changing the list item, while still maintaining its ability to execute to find the maximum value.
I have tried modifying the start_loop to include an addl data_items, 0x01 but it errors out since it only pulls the first value.
I then adjusted it to do something like addl data_items(,%esi,4), 0x01 and iterate through adjusting it but that didn't work either. I know this is probably very simplistic, but I can't seem to find a method that works.
#
.section .data
data_items: #These are the data items trying to modify and store
.long 3,67,34,222,45,75,54,34,44,33,22,11,66,0
.section .text
.globl _start
_start:
movl $0, %edi
movl data_items(,%edi,4), %eax
movl %eax, %ebx
start_loop:
cmpl $0, %eax
je loop_exit
incl %edi
movl data_items(,%edi,4), %eax
cmpl %ebx, %eax
jle start_loop
movl %eax, %ebx
jmp start_loop
loop_exit:
movl $1, %eax
int $0x80
Once you have an array element in %eax just increment the memory that was last used to read %eax from:
start_loop:
cmpl $0, %eax ; Not actual element if this is 0
je loop_exit
incl data_items(,%edi,4) <<<<<<<<<<<<<<<<<
incl %edi
movl data_items(,%edi,4), %eax
This does not mess with the current finding of the max value. Only next time will the max value be 1 greater.

%al register in C code

testb $1, %al
je .L3
leal 1(%eax,%eax,2), %eax
jmp .L4
I am given the above assembly code and asked to translate it to c code.
I know what almost all of it is doing, I just don't know how to to do C code for the %al register.
Here Is the rest of the assembly code if it helps
prob2:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
cmpl $1, %eax
je .L1
.L6:
testb $1, %al
je .L3
leal 1(%eax,%eax,2), %eax
jmp .L4
.L3:
shrl %eax
.L4:
cmpl $1, %eax
jne .L6
.L1:
popl %ebp
ret
Doesn't matter here. Bit0 in AL is the same as Bit0 in EAX. The 8-bit operation was surely an optimization of the compiler. So you can read AL as EAX.

Cmp instruction mismatch

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?

Loop Assembly x86

I am a beginner in Assembly(x86 ATT Syntax). I am working on an assignment where I have to go through each index of a 2d array and find the number of 1's. The method takes in 2d int array,int w, int h. How do I implement the loop to go go from 0 to w and bounce out with loop instruction. I know how to do it with a jmp instruction but loop just gives me errors/segFaults. This is my attempt with a jump statement and it works. How would I go about converting the inner loop using a loop instruction?
pushl %ebp
movl %esp, %ebp
movl $0, -4(%ebp)
movl $0, -8(%ebp)
movl $0, -12(%ebp)
movl $0, -4(%ebp) #outside loop
jmp .L10
.L14: #Inner Loop
movl $0, -8(%ebp)
jmp .L11
.L13:
movl -4(%ebp), %eax
leal 0(,%eax,4), %edx
movl 8(%ebp), %eax
addl %edx, %eax
movl (%eax), %eax
movl -8(%ebp), %edx
sall $2, %edx
addl %edx, %eax
movl (%eax), %eax
cmpl $1, %eax
jne .L12
addl $1, -12(%ebp)
.L12:
addl $1, -8(%ebp)
.L11: #check inner loop
movl -8(%ebp), %eax
cmpl 12(%ebp), %eax
jl .L13
addl $1, -4(%ebp)
.L10: #check outside loop
movl -4(%ebp), %eax
cmpl 16(%ebp), %eax
jl .L14
movl -12(%ebp), %eax
leave
ret
Generally using loop has no advantages except maybe smaller code. It's usually slower and less flexible, thus not recommended.
That said, if you still want to use it you should know that it employs the ecx register for counting down to zero. So you need to restructure your code to accommodate that. In your case, that means loading ecx with the value of w and letting it count down. You will also need to apply an offset of -1 during indexing, since your current loop variable goes from 0 to w-1, but ecx will go from w down to 1 (inclusive).
Furthermore, the loop instruction is used after the loop body, that is it implements a do-while loop. To skip the loop body if the count is zero a companion instruction, JECXZ, can be used.
You can use lodsl (which moves %esi up by default) and loop (which moves %ecx down) in tandem. I am not sure if it is more efficient than what gcc generates from c, which is basically your code, but it looks prettier.
What I have done here doesn't answer your question precisely -- rather than use loop for the inner loop I have assumed the whole array is stored contiguously and then there is only a single loop to worry about. When compiling from c on my machine, it is stored contiguously, but I'm not sure you should rely on that. Hopefully what I have done gives you enough to understand how loop and lodsl work, and you can modify your code to use them just in the inner loop.
.data
x:
.long 6
y:
.long 5
array:
.long 1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1
.text
.global _start
_start:
# set up for procedure call
push x
push y
push $array
# call and cleanup
call cnt
add $0xc, %esp
# put result in %ebx and finish up
#(echo $? gives value in bash if <256)
mov %eax, %ebx
mov $1, %eax
int $0x80
# %ebx will hold the count of 1s
# %ecx will hold the number of elements to check
# %esi will hold the address of the first element
# Assumes elements are stored contiguously in memory
cnt:
# do progogue
enter $0, $1
# set %ebx to 0
xorl %ebx, %ebx
# grab x and y parameters from stack and
# multiply together to get the number of elements
# in the array
movl 0x10(%ebp), %eax
movl 0xc(%ebp), %ecx
mul %ecx
movl %eax, %ecx
# get address of first element in array
movl 0x8(%ebp), %esi
getel:
# grab the value at the address in %esi and increment %esi
# it is put in %eax
lodsl
# if the value in %eax is 1, increment %ebx
cmpl $1, %eax
jne ne
incl %ebx
ne:
# decrement %ecx and if it is greater than 0, keep going
loop getel
# %ecx is zero so we are done. Put the count in %eax
movl %ebx, %eax
# do epilogue
leave
ret
It really is prettier without all the comments.
.data
x:
.long 6
y:
.long 5
array:
.long 1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1
.text
.global _start
_start:
push x
push y
push $array
call cnt
add $0xc, %esp
mov %eax, %ebx
mov $1, %eax
int $0x80
cnt:
enter $0, $1
xorl %ebx, %ebx
movl 0x10(%ebp), %eax
movl 0xc(%ebp), %ecx
mul %ecx
movl %eax, %ecx
movl 0x8(%ebp), %esi
getel:
lodsl
cmpl $1, %eax
jne ne
incl %ebx
ne:
loop getel
movl %ebx, %eax
leave
ret

I'm trying to interpret this IA32 assembly language 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;
}

Resources