I have tried to write an insertion sort in assembly (nasm), and it doesn't work (always sent segmentation fault).
I tried to search the source of the problem for really long time and I cannot find it,
can someone please help me to find the problem?
thank you.
sort:
pushad
mov ebp,esp;creating stack frame
mov ebx,[ebp+36]; ebx saves pointer to the array
mov ecx,[ebp+40];ecx saves the srray size
mov esi,4 ; i
for_l1:
;edx=temp,esi=i,edi=j
mov edx,[ebx+esi]
mov edi,esi;j=i
sub edi,4;j=i-1
while_l1:
cmp edx,[ebx+edi]; if(temp<array[j])
jge end_while1
;array[j+1]=array[j], j-=1
mov eax,[ebx+edi]
mov [ebx+edi+4],eax
sub edi,4
cmp edi,0
jge while_l1;if(j>=0)
end_while1:
;array[j+1]=temp
mov[ebx+edi+4],edx
add esi,4;i+=1
dec ecx; decreasing the size of the array needed to sort
cmp ecx,1;if(size==1)
jg for_l1
finished1:
popad
ret 8
Are you sure array size represents the number of elements and that it doesn't contain the total length of the array?
Then perhaps you could code
mov ecx,[ebp+40];ecx saves the srray size
shr ecx,2
Related
From my previous question, I asked how to change the nation code to what I needed it to be. I explored in the disassembly more and I found out exactly where I needed this change to be. In other files, the code seems to be:
mov ds:dword_73A9C8, 1
Where the file I'm trying to edit has it like
mov ds:dword_73A9C8, eax
I've tried to edit the file in IDA by hex to match it to the first line of code, however, the function, even after extending its length, seems to break each time I edit it.
The question I have is how can I change it from having eax being moved to having 1 being moved without breaking the function
sub_4A2B60 proc near
arg_0= dword ptr 4
mov eax, [esp+arg_0]
mov ds:dword_73A9C8, eax
retn
sub_4A2B60 endp
You could replace the 4 byte instruction mov eax, [esp + 4] with the sequence xor eax, eax inc eax nop that also has 4 bytes.
If 1 is what you want, then the return value in EAX should probably also be 1.
So I am working on a Binary Bomb assignment and have gotten stuck. Tried looking at other questions and guides but mine seems to be completely different from what is described in other questions and guides I found on the web.
The phase only takes 2 unsigned ints for input. Here it is disassembled in gdb after being run with 11 2 as input.
Dump of assembler code for function phase_5:
0x08048ccc <+0>: push %ebp
0x08048ccd <+1>: mov %esp,%ebp
0x08048ccf <+3>: push %esi
0x08048cd0 <+4>: push %ebx
=> 0x08048cd1 <+5>: sub $0x20,%esp
0x08048cd4 <+8>: lea -0x10(%ebp),%eax
0x08048cd7 <+11>: mov %eax,0xc(%esp)
0x08048cdb <+15>: lea -0xc(%ebp),%eax
0x08048cde <+18>: mov %eax,0x8(%esp)
0x08048ce2 <+22>: movl $0x8049b0a,0x4(%esp)
0x08048cea <+30>: mov 0x8(%ebp),%eax
0x08048ced <+33>: mov %eax,(%esp)
0x08048cf0 <+36>: call 0x8048788 <__isoc99_sscanf#plt>
0x08048cf5 <+41>: cmp $0x1,%eax
0x08048cf8 <+44>: jg 0x8048cff <phase_5+51>
0x08048cfa <+46>: call 0x80492b6 <explode_bomb>
0x08048cff <+51>: mov -0xc(%ebp),%eax
0x08048d02 <+54>: and $0xf,%eax
0x08048d05 <+57>: mov %eax,-0xc(%ebp)
0x08048d08 <+60>: cmp $0xf,%eax
0x08048d0b <+63>: je 0x8048d36 <phase_5+106>
0x08048d0d <+65>: mov $0x0,%ecx
0x08048d12 <+70>: mov $0x0,%edx
0x08048d17 <+75>: mov $0x8049960,%ebx
0x08048d1c <+80>: add $0x1,%edx
0x08048d1f <+83>: mov (%ebx,%eax,4),%eax
0x08048d22 <+86>: add %eax,%ecx
0x08048d24 <+88>: cmp $0xf,%eax
0x08048d27 <+91>: jne 0x8048d1c <phase_5+80>
0x08048d29 <+93>: mov %eax,-0xc(%ebp)
0x08048d2c <+96>: cmp $0xb,%edx
0x08048d2f <+99>: jne 0x8048d36 <phase_5+106>
0x08048d31 <+101>: cmp -0x10(%ebp),%ecx
0x08048d34 <+104>: je 0x8048d3b <phase_5+111>
0x08048d36 <+106>: call 0x80492b6 <explode_bomb>
0x08048d3b <+111>: add $0x20,%esp
0x08048d3e <+114>: pop %ebx
0x08048d3f <+115>: pop %esi
0x08048d40 <+116>: pop %ebp
0x08048d41 <+117>: ret
For the line 0x08048d17 <+75>: mov $0x8049960,%ebx
I used
x/16b 0x8049960
gdb and it tells me
0x8049960 array.2954: 10 0 0 0 2 0 0 0
0x8049968 array.2954+8: 14 0 0 0 7 0 00
When I go through the program using until until I get to
0x08048d31 <+101>: cmp -0x10(%ebp),%ecx
%edx = 11, %ecx = 82, and %ebp-0x10 = 2 (used print to get values for first two and x/d $ebp-0x10 for last one)
Because 82 != 2 it just goes to call explode_bomb.
From what I understand it is reading in my 2 numbers, making sure I entered 2 at <+41>.
Then it grabs the first number from the array which in this case is 10 and puts it into $eax at +=<+51>. Then it puts eax into -0xc($ebp) at <+57>.
Then it checks to make sure $eax isn't 15 at <+60>, goes on to set $ecx, and $edx to 0. It then passes the pointer to the array to $ebx at <+75>.
Then it enters a loop from <+80> to <+91> but I am not sure what it is really doing. I get that it increments $edx by 1 and the loop is exited when $eax is 15, but I cant figure out how the rest of the stuff works out.
Am I understanding it correctly up to the loop part? And, if someone wouldn't mind explaining what is happening between <+80> and <+91> I would be very grateful.
p.s. Sorry if my formatting is wrong.
Then it grabs the first number from the array which in this case is
10 and puts it into $eax at +=<+51>.
Wrong. <+51> reads the first number you entered, not the first number from the array. It's then masked into the 0..15 range by discarding the top bits, and is written back to the local variable where it came from. It also lives on in eax, of course.
The array contains 4 byte integers and there are 15 of them. As such you can print it using x/15wd.
Now to the loop. edx is obviously just keeping track of the iteration count, no surprise there. <+83> is the interesting part: it replaces eax with the value of the array item whose index eax currently holds. That is eax = array[eax]. ecx is of course just summing up the array elements you have visited, that's again easy. The exit condition is when you hit the array item that has value 15.
What it all boils down is that this array is really a linked list. The end of the list is marked by a 15. The first number you enter is used as a starting point for list traversal. It should be selected such that you have 11 elements until the end of the list (see <+96>). The second input number should equal the sum of the array items visited.
I am using the following ASM routine to bubble sort an array. I want to know of the inefficiencies of my code:
.386
.model flat, c
option casemap:none
.code
public sample
sample PROC
;[ebp+0Ch]Length
;[ebp+08h]Array
push ebp
mov ebp, esp
push ecx
push edx
push esi
push eax
mov ecx,[ebp+0Ch]
mov esi,[ebp+08h]
_bubbleSort:
push ecx
push esi
cmp ecx,1
je _exitLoop
sub ecx,01h
_miniLoop:
push ecx
mov edx,DWORD PTR [esi+4]
cmp DWORD PTR [esi],edx
ja _swap
jmp _continueLoop
_swap:
lodsd
mov DWORD PTR [esi-4],edx
xchg DWORD PTR [esi],eax
jmp _skipIncrementESI
_continueLoop:
add esi,4
_skipIncrementESI:
pop ecx
loop _miniLoop
_exitLoop:
pop esi
pop ecx
loop _bubbleSort
pop eax
pop esi
pop edx
pop ecx
pop ebp
ret
sample ENDP
END
Basically I have two loops, as usual for the bubble sort algorithm. The value of ecx for the outer loop is 10, and for the inner loop it is [ecx-1]. I have tried the routine and it compiles and runs successfully, but I am not sure if it is efficient.
There are several things you can do to speed up your assembly code:
don't do things like ja label_1 ; jmp label_2. Just do jbe label_2 instead.
loop is a very slow instruction. dec ebx; jnz loopstart is much faster
use all registers instead of repeatedly push/pop ecx and esi. Use ebx and edi too.
jmp-targets should be well aligned. Use align 4 before the two loop-starts and after the jbe
Get yourself a manual for your cpu from Intel (you can download it as pdf), it has the timings for the opcodes, maybe it has other hints too.
Several simple tips:
1) Try to minimize the number of conditional jumps, because they are very expensive. Unroll if possible.
2) Reorder instructions to minimize stalls because of data depencency:
cmp DWORD PTR [esi],edx ;// takes some time to compute,
mov edx,DWORD PTR [esi+4] ;
ja _swap ;// waits for results of cmp
3) Avoid old composite instructions (dec, jnz pair is faster than loop and is not bound to ecx register)
It would be quite difficult to write assembly code that is faster than the code generated by optimizing C compiler, because you should consider lots of factors: size of data and instruction caches, alignments, pipeline, instruction timings. You can find some good documentation about this here. I especially recommend the first book: Optimizing software in C++
Substitute for "add esi,4" if we do not need a flag for this instruction:
_continueLoop:
lea esi,[esi+4]
So I'm coding out an insertion sort (in assembly) based on this high level code:
void insertionSort(int data[ ], int arraySize) {
int insert;
int moveItem;
for(int next=1; next<arraySize; next++) {
insert=data[next]; //store the value in the current element
moveItem=next; //initialize location to place element
while((moveItem>0)&&(data[moveItem-1]>insert)) {
//shift element one slot to the right
data[moveItem]=data[moveItem-1];
moveItem--;
} //end while
data[moveItem]=insert;
} //end for
} //end insertionSort
There are exactly 20 random numbers in an array called myArray. I cannot use an of the decision derivatives that come in the library that comes with our book. So basically movs, cmps, loops, and jumps
Here's what I got. I had it sorting the first of 20 random numbers earlier, but I've confused myself to death and have no idea what I'm doing any more. It crashes when it gets to the insertion sort method. Help please.
TITLE Insertion Sort (main.asm)
INCLUDE Irvine32.inc
.data
elems = 20
myArray sdword elems dup(0)
str1 byte "Press enter" ,0
str2 byte "The array now is ",0
next sdword 1
start sdword ?
.code
main PROC
call Clrscr
call CreateRandom
call Display
call InsertionSort
call Display
exit
main ENDP
CreateRandom PROC
;;;;Creates 20 random numbers and populates myArray;;;;;
call Randomize
mov ecx, 20
mov edx, OFFSET myArray
L1:
call Random32 ;create random number
mov [edx], eax ; move random number to the appropriate spot in the array
add edx, 4 ; increase the address of what it is pointing to
loop L1
mov edx, OFFSET str1 ; "press enter to continue"
call WriteString
call ReadInt
call Crlf
ret
CreateRandom ENDP
Display PROC
;;;; Displays current form of the array myArray;;;;;
mov edx, OFFSET str2 ; "The array now is:"
call WriteString ; write string
call Crlf
mov esi, OFFSET myArray ; offset of the array
mov ecx, 20 ; index of the loop
L2:
mov eax, [esi] ; move array at that point to eax
call WriteDec ; print out the array as a decimal
call Crlf ; next line
add esi, 4 ; next element in the array
loop L2
call Crlf
ret
Display ENDP
InsertionSort PROC
mov ecx, 19
mov edx, OFFSET myArray
mov ebx, OFFSET myArray ; eax=next
add ebx, 4 ;moves up the array to second element comparable to next
outterloop:
mov esi, [ebx] ; esi=data[next]
mov eax, ebx ;movelterm=ebx
L1:
mov edx, [eax-4] ;move the number that is greater into edx
mov [eax], edx ;move the number into that 2nd element of the
sub eax, 4
mov esi, [eax]
cmp eax, [edx]
JNG endinner ; if the address is not greater than the first address, skip to the end
mov edx, [eax-4]
cmp edx, esi ; if the address is greater, than it already sorted, skip to end
JG endinner
loop L1
endinner:
mov [eax], esi ; move first to the second to finish the sort
add ebx, 4 ;move to the next element of the array
inc next ;counting outside loop
cmp ecx, next
JNE outterloop ;return to top of for loop
ret
InsertionSort ENDP
END main
I haven't examined your code in detail, but I notice that InsertionSort seems to be using edx for two different purposes at once: as a pointer into the array, and to hold one of the values from the array. This will certainly break even if nothing else is wrong.
So, at the start of InsertionSort you say mov edx, OFFSET myArray -- it's a pointer into the array. Then, a few lines later, mov edx, [eax-4] -- oops, no, it's a value from the array. And a few lines later again, cmp eax, [edx] -- oh, no, now it's a pointer into the array again.
Perhaps that last instruction should be cmp edx, [eax] or something? Because eax does seem to be a pointer into the array here.
First of all, thanks for all the help thus far.
Complete code can be found here
I have trouble understanding these lines. I wrote some comments...
The line, for example, mov es:[si+6], al means move data in al to the memory address marked by si+6 (I think this would be an offset calculation).
Then what is add si,40 in the loop?
Any helps mean everything to me! Thank you.
L0_95: ; this segment prints ASCII code 0 - 95
mov si,6 ; refers to the string we declared at the beginning
mov cx,4 ; I think this is the height?
C1A:
; this loop adds the name of the column
mov al,string[0]
mov es:[si],al
mov al,string[2]
mov es:[si+6],al
mov al,string[4]
mov es:[si+24],al
mov al,string[6]
mov es:[si+28],al
add si,40 ;;;; what is this line?
loop C1A
mov si,122 ;;;; and these three lines?
mov bx,0
mov cx,4
C1B:push cx
mov cx,24
add si,40
C1C:push cx
call DEC_CONVERT
add si,2
call HEX_CONVERT
add si,2
call BIN_CONVERT
add si,2
call CHAR_CONVERT
inc bx
add si,126
pop cx
loop C1C
pop cx
sub si,3840
loop C1B
ret
L96_191:
add si advances the si register by 40.
mov si,122 sets the si register to 122, probably the address of some data. The remaining two instructions should now be self-explanatory.