Related
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.
I have a little program written with c and assembly. the principle is simple: "count the '0's in a a string given by main.c
so for test0 str0ing 0 it should return 3 because there's 3 '0's in the string
the function itself is made in x86 asm with AT&T syntax, i am given a pointer to the string via C. both main.c and the asm is linked via header file.
this is my code so far and the problem is that it always returns 0. it never reaches conditional jump to increment %eax(to be returned)
// C
#include "asm.h"
char string[] = "2a0 a0 ";
char *ptr1 = string;
int main(){
printf("\nthere are : %d %s in :%s", zero_count(), "0s", string);
printf("\nstring address is: %p\n", ptr1);
return 0;
}
// x86asm
.global ptr1
.section .text
.global zero_count #func()
zero_count:
# prologue
pushl %ebp # save these previous stack frame pointer
movl %esp, %ebp # the stack frame pointer for function
# save registers
#pushl $ebx # needs to be pushed out of stack when used
#pushl %esi # needs to be pushed out of stack when used
#pushl %edi # needs to be pushed out of stack when used
# function body
movl ptr1, %ecx # moves the value of ptr1 to ecx
movl $0, %eax # cleans eax with 0
# loop start
loop_beginning:
cmp $0, (%ecx)
je end
# compare to 'o'
cmp $48, %ecx # 48 is "0" in the asci table
je if_0
increment_pointer:
addl $1, %ecx
jmp loop_beginning
if_0:
addl $1, %eax
jmp increment_pointer
end:
#popl %edi # needs to be popped when used
#popl %esi # needs to be popped when useds
#popl %ebx # needs to be popped when used
# epilogue
movl %ebp, %esp # restore the previous stack pointer("cleaner" the stack)
popl %ebp # restore the previous stack frame pointer
ret #w returns
i apolagize for using global variables in advance, i know it's not good but I'm still learning to use the stack
by switching the cmp to cmpb worked in this string. but i still don't know why. would this operation also worked if this was an int[]?
.global ptr1
.section .text
.global zero_count #func()
zero_count:
# prologue
pushl %ebp # save these previous stack frame pointer
movl %esp, %ebp # the stack frame pointer for function
# save registers
#pushl $ebx # needs to be pushed out of stack when used
#pushl %esi # needs to be pushed out of stack when used
#pushl %edi # needs to be pushed out of stack when used
# function body
mov ptr1, %ecx # moves the value of ptr1 to ecx
movl $0, %eax # cleans eax with 0
# loop start
loop_beginning:
cmpb $0, (%ecx)
je end
# compare to 'o'
cmpb $48, (%ecx) # 48 is "0" in the asci table
je if_0
increment_pointer:
addl $1, %ecx
jmp loop_beginning
if_0:
addl $1, %eax
jmp increment_pointer
# movl (%ecx), %eax
end:
#popl %edi # needs to be popped when used
#popl %esi # needs to be popped when useds
#popl %ebx # needs to be popped when used
# epilogue
movl %ebp, %esp # restore the previous stack pointer("cleaner" the stack)
popl %ebp # restore the previous stack frame pointer
ret #w returns
I'm trying to link assembly functions to a C code for exercise.
Here's my assembly function, written in x86 assembly:
.code32
.section .text
.globl max_function
.type max_function, #function
# i parametri saranno in ordine inverso a partire da 8(%ebp)
max_function:
pushl %ebp # save ebp
movl %esp, %ebp # new frame function
movl $0, %edi # first index is 0
movl 8(%ebp), %ecx # ecx is loaded with the number of elements
cmpl $0, %ecx # check that the number of elements is not 0
je end_function_err #if it is, exit
movl 12(%ebp),%edx # edx is loaded with the array base
movl (%edx), %eax # first element of the array
start_loop:
incl %edi #increment the index
cmpl %edi,%ecx #if it's at the end quit
je loop_exit
movl (%edx,%edi,4),%ebx #pick the value
cmpl %ebx,%eax #compare with actual maximum value
jle start_loop #less equal -> repeat loop
movl %ebx,%eax #greater -> update value
jmp start_loop #repeat loop
loop_exit:
jmp end_function #finish
end_function: #exit operations
movl %ebp, %esp
popl %ebp
ret
end_function_err:
movl $0xffffffff, %eax #return -1 and quit
jmp end_function
It basically defines a function that finds the maximum number of an array (or it should be)
And my C code:
#include <stdio.h>
#include <stdlib.h>
extern int max_function(int size, int* values);
int main(){
int values[] = { 4 , 5 , 7 , 3 , 2 , 8 , 5 , 6 } ;
printf("\nMax value is: %d\n",max_function(8,values));
}
I compile them with gcc -o max max.s max.c.
I get a SegmentationFault when executing the code.
My suspect is that I don't access the value in a right manner, but I can't see why, even because I based my code on an example code that prints argc and argv values when called from the command line.
I'm running Debian 8 64-bit
The problems were:
not preserving %ebx and %edi
not compiling for 32 bit (had to use -m32 flag for gcc)
cmpl operands were inverted
Thanks everybody, problem is solved.
I'll focus more on debugging tools to (disassembling and running step by step was very useful)!
.data
arr: .long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
arr_size: .long 10
in: .string "%d"
.text
.global main
main:
#scanf
movl $0, %ecx # index i
scanloop:
cmpl arr_size, %ecx
je endscan # if ecx == 10 -> break
leal arr(, %ecx, 4), %eax # load the address of arr[i] into eax
pushl (%eax) # push the value that is being pointed at onto the stack
pushl $in
call scanf
addl $8, %esp
incl %ecx
jmp scanloop
#endscanf
endscan:
#...
I don't know how to "scanf" values into an array. I thought it'd work if I calculate the address of each index, push the value that the address points to onto the stack and call scanf. But I get a memory access error.
So, is there a way to do it like that?
For reasons I cannot tell it works if I use %edi instead of %ecx as my index.
I still don't know how to use a debugger, so I printed out my index in every iteration to see what's wrong. The thing was that %ecx never got beyond 1, which made the procedure stuck in an infinite loop.
With %edi, however, incrementation works perfectly fine.
PS: Out of curiosity I've tried other registers as well, namely %esi and %ebx. It also works for them. If I ever find out the reasons for this, I'll refer back to this post.
Edit: Ok, the mistake was a silly one. I didn't obey to the calling conventions.
So scanf, like printf, apparently changes register values. By convention, %eax, %ecx and %edx are caller-save, whereas %ebx, %edi and %esi are callee-save.
Because I, as the caller, didn't save %ecx prior to the call to scanf, I got an unwanted value in %ecx.
It worked for %edi, %esi and %ebx because these are callee-save, hence guaranteed to be not changed by the called function. So if I had tried %eax or %edx instead, it most likely wouldn't have worked either.
And yes, it works perfectly fine if I push %ecx on the stack before calling scanf.
Edit2:
Oh, and solved the issue with the access problem by making myself a global variable in which I scan a number, and move that number into the desired index:
.data
num: .long 0
#...
scanloop:
cmpl arr_size, %ecx
je endscan # if ecx == 10 -> break
pushl %ecx #caller-save
pushl $num
pushl $in
call scanf
addl $8, %esp
popl %ecx #restore
movl num, %eax #in order to avoid two memory arguments to movl
leal arr(, %ecx, 4), %edx #calculate address of index
movl %eax, (%edx) #store num in that index
incl %ecx
jmp scanloop
#endscanf
#...
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