This is the same as the one above. 13-digit parameter is stored as a char* pointed at by <FIX>esi</FIX>. Can you convert this to C?
lea edi, [esi+0Bh]
mov ecx, 0C2h
top:
mov eax, ecx
mov ebx, 0Ch
cdq
idiv ebx
mov al, [edi]
sub ecx, 11h
dec edi
cmp ecx, 7
mov bl, [edx+esi]
mov [edi+1], bl
mov [edx+esi], al
jge top
Solution (in plain C this time):
Quotevoid shuffleStarcraftCDKey(char *CDKey)
{
int i;
int edi = 0x0b;
for(i = 0xC2; i >= 7; i -= 0x11)
swap(&CDKey[edi--], &CDKey[i % 0x0C]);
}
Interesting. What does esi contain at the beginning?
Sorry, I made a mistake typing that. It's fixed and I put <FIX> tags around it.
My bad :)
I don't believe swap() is in the Standard C Library.
Quote from: Maddox on March 16, 2004, 08:26 PM
I don't believe swap() is in the Standard C Library.
I forgot to say, in my solution I used a "swap" function I didn't include, you can assume it exists :)
I got the same solution as you iago. It looks like cdq is just there to set edx = 0. What's the advantage of this over xor edx, edx? I've seen the cdq - idiv combination several times.
I'm guessing that using cdq before a division is standard. That's the first time I seen it, but that's perfectly logical.
One thing is, say eax is negative. The cdq will make sure that the div uses the negative number and not the equivolant positive. The sign extension is important.
I know that this number *can't possibly* be negative, so it would be no change (and perhaps an optimization) to do xor edx, edx, but that wouldn't always work.
Quote from: iago on March 17, 2004, 08:07 AM
I'm guessing that using cdq before a division is standard. That's the first time I seen it, but that's perfectly logical.
One thing is, say eax is negative. The cdq will make sure that the div uses the negative number and not the equivolant positive. The sign extension is important.
I know that this number *can't possibly* be negative, so it would be no change (and perhaps an optimization) to do xor edx, edx, but that wouldn't always work.
Sounds to me like the programmer used
int needlessly instead of
unsigned. Don't do that!
Quote from: Skywing on March 17, 2004, 09:33 AM
Quote from: iago on March 17, 2004, 08:07 AM
I'm guessing that using cdq before a division is standard. That's the first time I seen it, but that's perfectly logical.
One thing is, say eax is negative. The cdq will make sure that the div uses the negative number and not the equivolant positive. The sign extension is important.
I know that this number *can't possibly* be negative, so it would be no change (and perhaps an optimization) to do xor edx, edx, but that wouldn't always work.
Sounds to me like the programmer used int needlessly instead of unsigned. Don't do that!
I suspect it was stored as a char*, so he put it into a char then did the arithmatic on it. If he had used an unsigned char, he would have had to cast it to that.
Which brings up an interesting question: why ARE chars signed by default?
They aren't. The signedness of char is implementation-defined, which is even worse. You can't rely on it being either signed or unsigned (unless explicitly qualifying the signed-ness; then again, signed char* is incompatible with char* which is incompatible with unsigned char*, so you have ugly casts needed for all stdlib string functions).
cl.exe provides a command-line switch to set the default char to act unsigned (it's default is signed). I don't know about any other compilers, though.
That's eww. We should all start using Java which uses wide characters by default (I screwed up a few times assuming that sizeof(char) == 1).
Quote from: Skywing on March 17, 2004, 10:54 AMcl.exe provides a command-line switch to set the default char to act unsigned (it's default is signed). I don't know about any other compilers, though.
gcc also has a switch for controlling this:
-fsigned-char and
-funsigned-char.
Quote from: iago on March 17, 2004, 11:28 AMThat's eww. We should all start using Java which uses wide characters by default (I screwed up a few times assuming that sizeof(char) == 1).
Java avoids this problem by not even supporting signed types properly! Just try declaring an unsigned 32bit quantity in Java. :)
Why would you ever have to? Well, the only time I've ever seen a need is in division. Java can do unsigned shifting in much the same was as assembly: different operator.
Quote from: iago on March 17, 2004, 12:38 PM
Why would you ever have to? Well, the only time I've ever seen a need is in division. Java can do unsigned shifting in much the same was as assembly: different operator.
Probably because unsigned numbers are (rightly) used all the time in The Rest Of The World, and despite Sun's best attempts, Java can't completely ignore reality.
Quote from: Skywing on March 17, 2004, 03:00 PM
Quote from: iago on March 17, 2004, 12:38 PM
Why would you ever have to? Well, the only time I've ever seen a need is in division. Java can do unsigned shifting in much the same was as assembly: different operator.
Probably because unsigned numbers are (rightly) used all the time in The Rest Of The World, and despite Sun's best attempts, Java can't completely ignore reality.
But,what would you need an unsigned number for that a signed number + unsigned operators can't handle?
In writing the functions to log onto battle.net (check revision, cdkey decode, broken sha-1) I never had to do anything weird to shift variables besides use the unsigned shift operator rather than the signed one (like assembly does).
Quote from: Maddox on March 17, 2004, 01:18 AM
I got the same solution as you iago. It looks like cdq is just there to set edx = 0. What's the advantage of this over xor edx, edx? I've seen the cdq - idiv combination several times.
It is standard to use cdq before idiv because idiv means signed division. It is standard to use xor before div because div means unsigned division. You should never see cdq div or xor idiv.
Quote from: iago on March 17, 2004, 03:08 PM
But,what would you need an unsigned number for that a signed number + unsigned operators can't handle?
In writing the functions to log onto battle.net (check revision, cdkey decode, broken sha-1) I never had to do anything weird to shift variables besides use the unsigned shift operator rather than the signed one (like assembly does).
You would need to support unsigned numbers to do lots of things (or go to a lot of [performance-degrading] trouble to work around it). For instance, sequence numbers in lots of network protocols are unsigned, and there are many file formats with unsigned numbers. In fact, if you were ever to try and process a .mpq file you downloaded from Battle.net within Java, you would probably run into problems with no unsigned support.
If you have all the unsigned operators available, then sure, you can use unsigned multiplication, unsigned division etc when they are needed, but it's a pain to remember to use the right multiplication operator every time compared to defining the signedness of a variable correctly once.
Quote from: Adron on March 17, 2004, 03:18 PM
If you have all the unsigned operators available, then sure, you can use unsigned multiplication, unsigned division etc when they are needed, but it's a pain to remember to use the right multiplication operator every time compared to defining the signedness of a variable correctly once.
Multiplication works out the same in both signed and unsigned, doesn't it?
Quote from: iago on March 17, 2004, 05:53 PM
Multiplication works out the same in both signed and unsigned, doesn't it?
No, multiplication is different for signed and unsigned.
Quote from: Adron on March 17, 2004, 05:58 PM
Quote from: iago on March 17, 2004, 05:53 PM
Multiplication works out the same in both signed and unsigned, doesn't it?
No, multiplication is different for signed and unsigned.
I can't think of any situation where that would happen, and I remember my digital logic prof explaining to us why, so I wrote a quick program to test it
#include <stdio.h>
int main()
{
for(int i = -10; i < 10; i++)
{
for(int j = -10; j < 10; j++)
{
int a = i;
int b = j;
unsigned int c = i;
unsigned int d = j;
if((int)(a*b) != (int)(c*d))
printf("doesn't match at %d %d", i, j);
}
}
return 0;
}
It outputs nothing. Can you come up with a case where it wouldn't? I'm testing both positive and negative numbers in every combination.
It matters when you use all of the result, i.e. multiplying two 32-bit numbers generates a 64-bit result.
Quote from: Adron on March 17, 2004, 07:33 PM
It matters when you use all of the result, i.e. multiplying two 32-bit numbers generates a 64-bit result.
hmm, I've never done or seen that before. How's that work in assembly?
Well, a similar example:
0CBC:0100 mov ax,8001
0CBC:0103 mov dx,ffff
0CBC:0106 imul dx
dx = 0, ax = 7fff
0CBC:0108 mov ax,8001
0CBC:010B mov dx,ffff
0CBC:010E mul dx
dx = 8000, ax = 7fff
Ah, so it works exactly reverse of division, using edx:eax. Neat! :)