Alright guys, I'm a total n00b to assembly. NOTE: I am not a student -- I am a professional lawyer who loves to tinker with the computer and waste time.
Using Visual Studio 2008 Express (C++), I actually managed to write a function in assembly language that evaluates a character, and if it is a lower case letter, returns the corresponding uppercase letter, if not a lower case letter, returns the same character evaluated.
I wrote this function in C++, assembly (in-line) and assembly (MASM).
Here is the C++ Code:
char cppToUpper(char c)
{
if (c > 122 || c < 97 )
return c;
else return c - 32;
}
Here is the inline assembly Code:
char cToUpper(int c)
{
//
//cout << cLowerLimit;
_asm
{
//Copy the character onto the arithmetic register for single bytes
mov eax, c;
//Test the Upper Limit
cmp eax, 122; // Compare the Character to 122
ja End; // Jump to the end if above -- the character is too high to be a lower case letter
//Test the lower limit
cmp eax, 97 //Compare the character to 97
jb End; // Jump to the end if below == the character is too low to be a lower case letter
//Now the operation begins
sub eax, 32; //Subtract 32 from the character in the register
End:
// mov result, al; //Move the Character in the register into the result variable
}
}
And here is the function in pure assembly language:
.686
.model flat, stdcall
option casemap :none
.code
cUpperCase2 proc cValue:DWORD
mov eax, cValue
cmp eax, 122
ja TEnd
cmp eax, 97
jb TEnd
sub eax, 32
TEnd:
ret
cUpperCase2 endp
end
Now, here is what the C++ function disassembles to:
char cppToUpper(char c)
{
01271680 push ebp
01271681 mov ebp,esp
01271683 sub esp,0C0h
01271689 push ebx
0127168A push esi
0127168B push edi
0127168C lea edi,[ebp-0C0h]
01271692 mov ecx,30h
01271697 mov eax,0CCCCCCCCh
0127169C rep stos dword ptr es:[edi]
if (c > 122 || c < 97 )
0127169E movsx eax,byte ptr [c]
012716A2 cmp eax,7Ah
012716A5 jg cppToUpper+30h (12716B0h)
012716A7 movsx eax,byte ptr [c]
012716AB cmp eax,61h
012716AE jge cppToUpper+37h (12716B7h)
return c;
012716B0 mov al,byte ptr [c]
012716B3 jmp cppToUpper+3Eh (12716BEh)
012716B5 jmp cppToUpper+3Eh (12716BEh)
else return c - 32;
012716B7 movsx eax,byte ptr [c]
012716BB sub eax,20h
}
012716BE pop edi
012716BF pop esi
012716C0 pop ebx
012716C1 mov esp,ebp
012716C3 pop ebp
012716C4 ret
ALRIGHT HERE'S the question. Why is the C++ code considerably faster even though it compiles to far more instructions than my assembly language code uses? 48 "ticks" expire when executing the pure assembly language function 10,000,000 times (I'll put this stuff at the very bottom); 0 ticks when executing it in C++, and 16 when using inline assembly?
I am impressed that I was even able to get it to work in assembly but perplexed at the performance results. I'll put the main() function below along with the efficiency timing stuff for your reference.
Any ideas? I am just trying to learn a little assembly because I am curious about how computers actually work.
Thanks,
Chris
#include "stdafx.h"
#include <iostream>
#include <string>
#include "windows.h"
#include "time.h"
using namespace std;
extern "C" int _stdcall cUpperCase2(char c);
class stopwatch
{
public:
stopwatch() : start(clock()){} //start counting time
~stopwatch();
private:
clock_t start;
};
stopwatch::~stopwatch()
{
clock_t total = clock()-start; //get elapsed time
cout<<"total of ticks for this activity: "<<total<<endl;
cout <<"in seconds: "<< double(total/CLK_TCK) <<endl;
}
void main()
{
bool bAgain = true;
while (bAgain)
{
// unsigned long lTimeNow = t_time;
char c = 'a';
char d = '!';
char e;
//cout << "A lowercase character will be converted to Uppercase:" << endl;
//cin >> c;
{
stopwatch watch;
for (int i=0; i < 10000000; i++)
{
e= cUpperCase2(c);
e= cUpperCase2(d);
}
}
cout << "That was the external function written in assembler." << endl;
{
stopwatch watch;
for (int i=0; i < 10000000; i++)
{
// cout << cppToUpper(c);
//cout << cppToUpper(d);
e= cppToUpper(c);
e= cppToUpper(d);
}
}
cout << "That was C++\n";
{
stopwatch watch;
for (int i=0; i < 10000000; i++)
{
e= cToUpper(c);
e= cToUpper(d);
}
}
cout << "That was in line assembler\n";
cout << "Enter a letter and hit enter to exit (a will repeat) . . ." << endl;
cin >> c;
//return 0;
if (c != 'a')
bAgain = false;
}
}