Archived

This topic is now archived and is closed to further replies.

ph33r

Why does this code work?

Recommended Posts

There must be something going on with the compiler that I don''t know about. If you notice after the while loop I do not return a value, but for some reason it does return the correct value. I''m very confused.
  
#include <iostream>

using namespace std;

int GCD(int, int);

int main()
{
	int x, y;

	cout << "Enter two integers\n1: ";
	cin >> x;
	cout << "2: ";
	cin >> y;
	cout << "The greatest common denominator of these numbers is " << GCD(x, y) << endl;
	system("PAUSE");

	return 0;
}

int GCD(int x, int y)
{
	int temp;

	if(x > y)
		if(x % y == 0)
			return y;
	if(y > x)
		if(y % x == 0)
			return x;



	while (x > 0)
	{
		temp = x;
		x = y % x;
		y = temp;
	}

}  

Share this post


Link to post
Share on other sites
Here is the dissassembly of your GCD function.


    
--- C:\Documents and Settings\Sysop\Desktop\Test\test.cpp -----------------------------------------------------------------
15:
16: int GCD(int x, int y)
17: {
00401920 push ebp
00401921 mov ebp,esp
00401923 sub esp,44h
00401926 push ebx
00401927 push esi
00401928 push edi
00401929 lea edi,[ebp-44h]
0040192C mov ecx,11h
00401931 mov eax,0CCCCCCCCh
00401936 rep stos dword ptr [edi]
18: int temp;
19: if(x > y)
00401938 mov eax,dword ptr [ebp+8]
0040193B cmp eax,dword ptr [ebp+0Ch]
0040193E jle GCD+30h (00401950)
20: if(x % y == 0)
00401940 mov eax,dword ptr [ebp+8]
00401943 cdq
00401944 idiv eax,dword ptr [ebp+0Ch]
00401947 test edx,edx
00401949 jne GCD+30h (00401950)
21: return y;
0040194B mov eax,dword ptr [ebp+0Ch]
0040194E jmp GCD+66h (00401986)
22: if(y > x)
00401950 mov ecx,dword ptr [ebp+0Ch]
00401953 cmp ecx,dword ptr [ebp+8]
00401956 jle GCD+48h (00401968)
23: if(y % x == 0)
00401958 mov eax,dword ptr [ebp+0Ch]
0040195B cdq
0040195C idiv eax,dword ptr [ebp+8]
0040195F test edx,edx
00401961 jne GCD+48h (00401968)
24: return x;
00401963 mov eax,dword ptr [ebp+8]
00401966 jmp GCD+66h (00401986)
25:
26: while (x > 0)
00401968 cmp dword ptr [ebp+8],0
0040196C jle GCD+66h (00401986)
27: {
28: temp = x;
0040196E mov edx,dword ptr [ebp+8]
00401971 mov dword ptr [ebp-4],edx
29: x = y % x;
00401974 mov eax,dword ptr [ebp+0Ch]
00401977 cdq
00401978 idiv eax,dword ptr [ebp+8]
0040197B mov dword ptr [ebp+8],edx
30: y = temp;
0040197E mov eax,dword ptr [ebp-4]
00401981 mov dword ptr [ebp+0Ch],eax
31: }
00401984 jmp GCD+48h (00401968)
32: }
00401986 pop edi
00401987 pop esi
00401988 pop ebx
00401989 mov esp,ebp
0040198B pop ebp
0040198C ret


If you notice, the compiler has assumed what should be returned, and it added that code for you.

I was wrong, read CWizards second post, and my post after that.

[edited by - yummy_potatoes on March 2, 2003 12:39:55 PM]

[edited by - yummy_potatoes on March 2, 2003 12:49:48 PM]

Share this post


Link to post
Share on other sites
I think this does not work, it just happen by chance to behave as expected. You should have a warning about that not all control paths return a value. This will cause the function to return an undefined value in those cases. In this case, probably whatever is in eax, which might be just what you intend to return. This is pure speculation, though.


Share this post


Link to post
Share on other sites
quote:
Original post by yummy_potatoes
If you notice, the compiler has assumed what should be returned, and it added that code for you.
No, i do not notice that. The value that the function returns is the value that is in eax when it comes back from the call. I can''t see that the compiler has inserted anything like that.


Share this post


Link to post
Share on other sites
Ahh, yes. It would indeed return whatever is in EAX, because that is the standard register for that kind of thing. I just now remembered that in MASM32, you get your return value from EAX after invoking a function.

Share this post


Link to post
Share on other sites
What exactly is the EAX register for, and why do they use it to store temporary values and the return value.

I tried looking it up and I found that AX was the incremental register though I didn''t see an EAX for. Also I stepped through the dissasembly and I saw that every temp variable the compiler used was stored in EAX.

Any incite would be helpfull.

Share this post


Link to post
Share on other sites
quote:
Original post by ph33r
What exactly is the EAX register for, and why do they use it to store temporary values and the return value.


EAX is merely an extended register. AX is a 16-bit register used mostly with old DOS programs. EAX has an extra 16 bits tacked onto it, making it 32 bit. Basically, they both serve the same purpose (accumulators).

Edit: as to why it's used to store temporary values, well, working with registers is a LOT faster than with RAM. Technically, you could stock temporary values in RAM, but it would be rather unefficient. For instance...
SomeValue = (SomeValue / 2) + (OtherValue - SomeValue) * 1.5
...would have to be transformed into...
TempA = OtherValue
TempA -= SomeValue
TempA *= 1.5
TempB = SomeValue
TempB /= 2
SomeValue = TempB
SomeValue += TempA
...which adds a good deal of overhead. You have to load and write variables a lot, and since assembly can only work with registers directly in the first place, you'd only end up wasting your time and chewing up unecessary cycles.

[edited by - RuneLancer on March 3, 2003 9:48:27 AM]

Share this post


Link to post
Share on other sites

+----------------------------------+
| EAX |
+----------------------------------+

+-----------------+----------------+
| Unnamed | AX |
+-----------------+--------+-------+

+-----------------+--------+-------+
| Unnamed | AH | AL |
+-----------------+--------+-------+

EAX refers to the full 32bits,
AX refers to the lower 16bits that EAX names,
AH refers to the upper 8bits that AX names,
AL refers to the lower 8bits that AX names.

I am unsure why it is used so much for strogin temporary values, but I think I read somewhere that it was faster (closer to the circuitry that actually performs the additions.)

And unlike RuneLancer said, it is my understanding (not sure, I am still learning ASM myself), that you can directly refer to RAM, but it is slow as hell compared to just using the CPU's built in memory.

[edited by - yummy_potatoes on March 3, 2003 2:03:12 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
study some CPU architechture and you will understand

Share this post


Link to post
Share on other sites
The reasons (E)AX is used to store temporary variables are as follows:

1. Certain instructions (f.i. mov, add, sub...) cannot accept arguments in the form mem32,mem32... that is the following is invalid:
mov tmp1,tmp2
Instead, you have to do the following:
mov ax,tmp1
mov tmp2,ax
Obviously, to just store tmp1->ax in the first place is more efficient than moving it into ax every time.

2. Certain other instructions (f.i. mul and imul) automatically use the (e)ax register to preform multiplication, that is the mul works as follows:
mov ax,tmp1
mul tmp2
mov result,ax
and not:
mul tmp1,ax ; or any similiar combination of operands

3. Add to that the fact that accessing registers is significantly faster than accessing memory (registers are on the processor whereas memory is usually located over a bus).

-- Exitus Acta Probat --

Share this post


Link to post
Share on other sites
quote:
Original post by jperalta
1. Certain instructions (f.i. mov, add, sub...) cannot accept arguments in the form mem32,mem32... that is the following is invalid:
mov tmp1,tmp2
Instead, you have to do the following:
mov ax,tmp1
mov tmp2,ax
Obviously, to just store tmp1->ax in the first place is more efficient than moving it into ax every time.

2. Certain other instructions (f.i. mul and imul) automatically use the (e)ax register to preform multiplication, that is the mul works as follows:
mov ax,tmp1
mul tmp2
mov result,ax
and not:
mul tmp1,ax ; or any similiar combination of operands
Yay, Intel!!! Not news to me, but no wonder noone wants to code assemebly on the x86.

It is quite understandable that it uses EAX for everything. When I code M680x0, i hardly use memory access at all, but manage with the 15 general purpose data and address registers. There is just no reason to take the bus to fetch memory and run out to store it all the time. I don''t know much (nor very interested) about modern processors, so this might not be accurate, but a register read/write should always take < 1 cycle, while a memory access can take forever (paging etc.).


Share this post


Link to post
Share on other sites
quote:
Certain other instructions (f.i. mul and imul) automatically use the (e)ax register to preform multiplication, that is the mul works as follows: [...]
and not:
mul tmp1,ax ; or any similiar combination of operands


jperalta: one of the imul forms can do dst = src * imm8, but otherwise you''re right. While it would be nice to have a competely orthogonal instruction set (hell, while I''m dreaming, tons of regs), that has not been any bother to me in the past. Other instructions that indirectly reference eax are div, BCD stuff, sign extension, and port I/O (none of which I have much use for).

The real reasons why eax is often used (as opposed to other regs):
1) ALU ops on eax don''t need a ModR/M byte (=> smaller code)
2) the calling convention says eax can be trashed; if we need to return something, might as perform the calculations on the reg directly.


> Yay, Intel!!! Not news to me, but no wonder noone wants to code assemebly on the x86.
hmm. I''d say that [mul implicitly uses eax] has pretty much zero impact on my coding assembly.

> It is quite understandable that it uses EAX for everything.
It ain''t that bad - there are all of 7 other general purpose regs for the taking

quote:
There is just no reason to take the bus to fetch memory and run out to store it all the time. I don''t know much (nor very interested) about modern processors, so this might not be accurate, but a register read/write should always take < 1 cycle, while a memory access can take forever (paging etc.).

Absolutely. That''s why in a pinch, esp is used as a general reg

Share this post


Link to post
Share on other sites