PDA

View Full Version : Assembly



Diaboli
25-09-2007, 11:19 AM
System: Dell M1710 (2,16GHz Duo|2048mb RAM|GeForce Go 7950GTX 512mb)
IDE: Delphi 2006
Lib: none

I trying to make a function that stuffs a single into a string.
A single is 4 bytes, so i thought it would be jsut as easy as stuffing an integer into a string, but i get a compile error ("Operand Size Mismatch") when i try to move the single into EAX. but a single is 4 bytes, and EAX has place for 4 bytes, so why doesent it work? an integer is 4 bytes too, and it works fine.


function IntToRaw(I: Integer): String;
var
S: Array[0..3] of Char;
Int: Integer;
begin
asm
MOV EAX,I //<- Works fine
MOV S,EAX
end;
for int := 3 downto 0 do
Result:= Result+S[int];
end;

function SingleToRaw(SI: Single): String;
var
S: Array[0..3] of Char;
I: Integer;
begin
asm
MOV EAX,SI //<- Operand size mismatch
MOV S,EAX
end;
for I := 3 downto 0 do
Result:= Result+S[I];
end;

JSoftware
25-09-2007, 11:27 AM
Why not use copymemory(or movemem or what it's called)

technomage
25-09-2007, 11:28 AM
Why not use FloatToStr or at least look at how FloatToStr is coded (to get an idea on how it's done), in Delphi or Free Pascal. it might give you some pointers.

Diaboli
25-09-2007, 11:54 AM
Why not use FloatToStr or at least look at how FloatToStr is coded (to get an idea on how it's done), in Delphi or Free Pascal. it might give you some pointers.

floattostr converts a float to a string representation of that float.

like:
f: Single = 1.526543;
s: string;

s:= floattostr(f);

then s is: "1.526543"

that is not what i need. i need the resulting string to be 4 bytes long, containing the data from the single.

besides: have you tried figuring out of that code? it looks like egyptian for me:P

a few lines of assembly, i can read, buti'm not too good at it, to say the least...

JSoftware
25-09-2007, 12:16 PM
type
TStrFloat = packed array[1..4] of char;

function IntToRaw(I: Integer): String;
begin
result := TStrFloat(I);
end;

SingleToRaw(SI: Single): String;
begin
result := TStrFloat(SI);
end;

technomage
25-09-2007, 12:21 PM
type
TStrFloat = packed array[1..4] of char;

function IntToRaw(I: Integer): String;
begin
result := TStrFloat(I);
end;

SingleToRaw(SI: Single): String;
begin
result := TStrFloat(SI);
end;

That is better than mine :)


function SingleToRaw(s: Single): string;
type
TFloatToByte = packed record
case Byte of
0: (s: Single);
1: (a:array[0..4] of Byte);
end;
var f: TFloatToByte;
i: Integer;
begin
f.s := s;
for I := 3 downto 0 do
Result:= Result+ Char(f.a[I]);
end;

JSoftware
25-09-2007, 12:33 PM
Well your's would probably be safer in the context of types. But you use 0..4 and if you used char's instead of bytes you could just implicitly cast a to a string

technomage
25-09-2007, 12:37 PM
That code was all from the head and not tested, so yes the Record Structure should be array[0..3] of char, that would remove need for the loop :)

jdarling
25-09-2007, 12:43 PM
Since I'm guessing that your doing this more for the learning element then for the actual usefulness of the code. Might I suggest you read up a bit more on assembly: http://courses.ece.uiuc.edu/ece390/books/labmanual/inst-ref.html

Thats one of the x86 assembly instruction set sites on the web. The intel specific is at http://www.intel.com/products/processor/manuals/index.htm

Why you would perform the move in assembly and then perform the loop in standard pascal is what is confusing to me. If your going to do it in assembly, perform the entire operation in assembly. Otherwise just use the code posted using records and arrays instead :).

Using MOVSB (Move Single Byte) would also make more sense if your wanting to reverse order the bytes on the out.

Example from Gavin's Guide to assembly (http://burks.brighton.ac.uk/burks/language/asm/)for moving a string (and yes, you could load your single instead and use decrement):
cld ; clear direction flag
mov si,OFFSET String1 ; make ds&#58;si point to String1
mov di,OFFSET String2 ; make es&#58;di point to String2
mov cx,18 ; length of strings - In your case this would be 4
rep movsb ; copy string1 into string2


BTW: Technomage, your array should be 0..3 not 0..4 and should be of type char instead of byte. I know the compilers take care of the matter for you, but since the cast is local it makes more sense to just have the type as Char to start with. That is, unless the 64 bit versions are suddenly going to re-define what a char is :).

Diaboli
25-09-2007, 07:08 PM
well, the code is actually highly useful to me. I am supposed to use it to send data between client and server for a rpg i'm trying to code.
of course, the project is not one i believe i will complete anytime soon, if ever, in the current form, but struggling with this kind of problems tears on my motivation.

I have, thanks to you guys, now gotten past this irritating problem.
I find it rather amusing that the solution was VERY similar to what i myself had tried. i believe the word "packed" is the largest difference.
funny that that word could have saved me 12 hours of "pulling my hair".

JSoftware
25-09-2007, 07:12 PM
hehe type packing is something I also very often forget when I port stuff :P

Why do you handle it as raw strings? What if you send a zero integer? It would make a string like this: #0#0#0#0. If at some point the string is seen as nullterminated the whole datapacket would be lost.

I haven't figured out when or not strings are defined as nullterminated. But I've had quite a few problems with it in delphi

Diaboli
25-09-2007, 08:13 PM
hmm... i have had no trubble with that...

i use Indy 10 for sockets (just figured out how to get it to listen properly, as you can see of my previous thread), and have made my own End-Of-Line, because the original one is just two bytes, that can easily be stumbled uppon in a packet. hterefor, my EOL is now: "'|NDPKG|'+EOL". To use it when sending, just add '|NDPKG|' to whatever you are sending, and it will work.

i am happy to give you my "ConvertUtils.pas", if it can help!
besides: you all have helped me fix some major bugs in it! :D

Hint: Look at my "StrToRaw" and "GetStr" functions :wink:


unit ConvertUtils;

interface

uses
Dialogs;

type
TStrArray4 = Array[1..4] of Char;
TStrArray8 = Array[1..8] of Char;

function ToRawString(P: PChar; Length: Integer) : string;
function StrToHex (Str: String) : String;
function HexToInt(s: string): Longword;
function HexToStr(HexStr: String): String;
function InvertHex(HexStr: String): String;
function InvertStr(Str: String): String;

function StrToRaw(S: String): String;
function BoolToRaw(B: Boolean): String;
function ByteToRaw(B: Byte): String;
function IntToRaw(I: Integer): String;
function Int64ToRaw(I: Int64): String;
function SingleToRaw(S: Single): String;

function GetInt(var RawStr: String): Integer;
function GetInt64(var RawStr: String): Int64;
function GetSingle(var RawStr: String): Single;
function GetByte(var RawStr: String): Byte;
function GetBool(var RawStr: String): Boolean;
function GetStr(var RawStr: String): String;

implementation

Uses StrUtils, SysUtils;

function StrToRaw(S: String): String;
begin
if (Length(S) <255>= 4) then
begin
IntStr:= TStrArray4(RawStr);
Delete(RawStr,1,4);
PI:= PInteger(IntStr);
Result:= PI^;
end
else
ShowMessage('GetInt: Raw String Too Short!');
end;

function GetInt64(var RawStr: String): Int64;
var
IntStr: TStrArray8;
PI: PInt64;
begin
// IntStr:= TStrArray8(RawStr);
Delete(RawStr,1,8);
// PI:= PInt64(IntStr);
Result:= PI^;
end;

function GetSingle(var RawStr: String): Single;
var
SingleStr: TStrArray4;
PS: PSingle;
begin
if (Length(RawStr) >= 4) then
begin
SingleStr:= TStrArray4(RawStr);
Delete(RawStr,1,4);
PS:= PSingle(SingleStr);
Result:= PS^;
end
else
ShowMessage('GetSingle: Raw String Too Short!');
end;

function GetByte(var RawStr: String): Byte;
var
PB: PByte;
ByteStr: String;
begin
if (Length(RawStr) >= 1) then
begin
//ByteStr:= LeftStr(RawStr,1);
Result:= Ord(RawStr[1]);
Delete(RawStr,1,1);
//PB:= PByte(@ByteStr);
//Result:= PB^;
end
else
ShowMessage('GetByte: Raw String Too Short!');
end;

Function GetStr(var RawStr: String): String;
var
LenByte: Byte;
IntStr: String;
begin
if (Length(RawStr) >= 1) then
begin
LenByte:= Ord(RawStr[1]);
Delete(RawStr,1,1);
if (Length(RawStr) >= LenByte) then
begin
Result:= LeftStr(RawStr,LenByte);
Delete(RawStr,1,LenByte);
end
else
ShowMessage('GetStr: Raw String Missing Data!');
end
else
ShowMessage('GetStr: Raw String Too Short!');
end;

Function GetBool(var RawStr: String): Boolean;
var
BoolByte: Byte;
begin
if (Length(RawStr) >= 1) then
begin
BoolByte:= GetByte(RawStr);
Result:= (BoolByte = 255)
end
else
ShowMessage('GetBool: Raw String Too Short!');
end;

Function InvertHex(HexStr: String): String;
var
i,j: Integer;
temp: String;
begin
i:= 0;
j:= (length(HexStr) div 2);
while i < j do
begin
temp:= temp+RightStr(HexStr,2);
HexStr:= LeftStr(HexStr,Length(HexStr)-2);
inc(i);
end;

Result:= temp;
end;

Function InvertStr(Str: String): String;
var
i,j: Integer;
temp: String;
begin
i:= 0;
j:= length(Str);
while i < j do
begin
temp:= temp+RightStr(Str,1);
Str:= LeftStr(Str,Length(Str)-1);
inc(i);
end;

Result:= temp;
end;

Function HexToStr(HexStr: String): String;
var
Buffer: Array of Byte;
i,j: Integer;
begin
i:= 0;
SetLength(Buffer, Length(HexStr) div 2);
j:= 1;
while i < Length(Buffer) do begin
Buffer[i]:= StrToInt('$'+ MidStr(HexStr,j,2));
Inc(j); Inc(j);
inc(i);
end;
Result:= ToRawString(PChar(Buffer),Length(Buffer));
end;

function HexToInt(s: string): Longword;
var
b: Byte;
c: Char;
begin
Result := 0;
s := UpperCase(s);
for b := 1 to Length(s) do
begin
Result := Result * 16;
c := s[b];
case c of
'0'..'9': Inc(Result, Ord(c) - Ord('0'));
'A'..'F': Inc(Result, Ord(c) - Ord('A') + 10);
else
raise EConvertError.Create('No Hex-Number');
end;
end;
end;

function StrToHex (Str: String) : String;
var
i, len: integer;
byte: string;

begin
len:= Length(Str);
i:= 1;

while i <len> 0) do begin
Result := result + c;
P := P + 1;
c := P^;
Length := Length - 1;
end;
end;

end.

Brainer
25-09-2007, 08:33 PM
Diaboli, I've sent you some examples. Did you take a look at them?

Diaboli
25-09-2007, 11:05 PM
yeah, it didnt compile :P
i think the forum changed some parts of it...

anyways: i got it working now, so :D

Parcel
26-09-2007, 05:42 AM
System: Dell M1710 (2,16GHz Duo|2048mb RAM|GeForce Go 7950GTX 512mb)
IDE: Delphi 2006
Lib: none

I trying to make a function that stuffs a single into a string.
A single is 4 bytes, so i thought it would be jsut as easy as stuffing an integer into a string, but i get a compile error ("Operand Size Mismatch") when i try to move the single into EAX. but a single is 4 bytes, and EAX has place for 4 bytes, so why doesent it work? an integer is 4 bytes too, and it works fine.


function IntToRaw(I: Integer): String;
var
S: Array[0..3] of Char;
Int: Integer;
begin
asm
MOV EAX,I //<- Works fine
MOV S,EAX
end;
for int := 3 downto 0 do
Result:= Result+S[int];
end;

function SingleToRaw(SI: Single): String;
var
S: Array[0..3] of Char;
I: Integer;
begin
asm
MOV EAX,SI //<- Operand size mismatch
MOV S,EAX
end;
for I := 3 downto 0 do
Result:= Result+S[I];
end;




function IntToRaw(I: Integer): String;
var
S: Array[0..3] of Char absolute I;
begin
result := S;
end;

function SingleToRaw(SI: Single): String;
var
S: Array[0..3] of Char absolute SI;
begin
result := S;
end;


:roll:

21o6
26-09-2007, 06:35 AM
SI is a 16-bit-register, so using mov EAX,SI tells the compiler to take 16-bit-SI and copy it to 32-bit-EAX, which he moarns about.
i've copied your source, renamed SI and it worked... altough the string was crap with a beep, actually :)

what do you need this for?

edit: "crap with a beep" = random ascii + the ascii-code for making a beep when outputting it via writeln *g*

21o6
26-09-2007, 06:54 AM
function SingleToRaw&#40;vSI&#58; Single&#41;&#58; String;
var
S&#58; Array&#91;0..3&#93; of Char;
p &#58; pointer;
I&#58; Integer;

begin
p &#58;= @vSI;
move&#40;byte&#40;p^&#41;,S&#91;0&#93;,4&#41;;
for I &#58;= 3 downto 0 do
singletoraw&#58;= singletoraw+S&#91;I&#93;;
end;


... this works. but i encourage you to write an assembler-version that works :) ... and look up the x86-registers! *gg*

edit: whoops, didn't realize the answers before mine. it's too early xDD

Diaboli
26-09-2007, 12:11 PM
ah... i thought it had checked that it wasnt a register.

i now have a strange problem, though:
when i use getint or getsingle, it sometimes doesent terurn the way it should.

for instance in my CharEnum:


procedure HandleCharEnum(Data: String);
var
Name : String;
Location : String;
HP,
MaxHP,
MP,
MaxMP : Single;
CharID : Integer;
SpriteID : Integer;
NumItems : Integer;

NewChar : TCharEnum;

ItmName : String;
ItmDesc : String;
ItmIcon: Integer;

i : Integer;
begin
Controller.CharEnums.Clear;
while Length(Data) > 31 do
begin
CharID := GetInt(Data);
GetInt(Data); <- had to add this
Name := GetStr(Data);
Location := GetStr(Data);
SpriteID := GetInt(Data);
GetInt(Data); <- had to add this
HP := GetSingle(Data);
MaxHP := GetSingle(Data);
MP := GetSingle(Data);
MaxMP := GetSingle(Data);
GetSingle(Data); <- I had to add this
NumItems := GetByte(Data);

Controller.CharEnums.Add(CharID,Name,Location,HP,M axHP,MP,MaxMP,SpriteID);

i:= 0;

while (i <NumItems> 10) do
begin
ItmName := GetStr(Data);
ItmDesc := GetStr(Data);
ItmIcon := GetInt(Data);
Controller.CharEnums.GetSelected.AddItem(ItmName,I tmDesc,ItmIcon);
Inc(i);
end;

end;
end;


i've marked the special stuff with "<- i had to add this".

the thing is: when a getsingle or getint is followed by some other get-function, it seems not to return properly. the getsingle randomly changed the MaxMP (before i added the ownerless GetSingle(Data; under it), and the CharID and SpriteID was left untouched (at their random init values, wich more often than rare is more than 400000)

I will see if i can rewrite the functions to assembly within the next few hours (got to eat first, and so on. i'm not THAT slow at writing code:P). but i have a poker tourney later today, so i expect i wont get much work done....

MVH
Diaboli

P.S:
heres a pic of the CharEnum screen, as it should be (some graphics are not properly made yet, so it doesent all match):
http://thorins.net/charenum.png