NASM Parsing Ascii Characters to display - parsing

Essentially what I wish to do (this is for an assignment) is have the user type in a character, and then display whether its an upper case/lower case letter, a 0-9 decimal, printable symbol, or a control key.
Unfortunately while the documentation gives me an idea as to fiddle with the control logic (if/else, loops, etc) actually knowing the commands to get NASM to do what I want it to do has been frustrating as the slides and class notes, and the documentation has not been entirely constructive.
Control Keys I believe are esc, null, tab, etc from DEC 0 to 32.
In my code below, I accept input from the user, but I don't think it accepts control keys, how would I fiddle it to do so?
segment .data
msg3 dw '10h'
segment .bss
;
aChar resb 2 ; reserve 10 bytes for aChar
segment .text
global _start
_start:
; ### Code for simple Input ###
mov eax, 3 ; select kernal call #3
mov ebx, 0 ; default input device
mov ecx, aChar ; pointer to aChar'
int 0x80 ; invoke kernal call to read
; ### Code to spit the input to the screen ###
mov eax, 4 ; select kernal call #4
mov ebx, 1 ; default output device
mov ecx, aChar ; pointer to ID
int 0x80 ; write id read
; termination code
exit: mov ax, 1 ; select system call #1 system exit
mov bx, 0 ; 0 means normal
int 0x80 ; invoke kernal call
So what I am thinking, assuming I am able to accept control keys in ascii. Is that once a user inputs a character, I convert it to hex or decimal, whichever is easier and then run if else cases wherein if its between certain values its an X, and then display X, if its between 2 different values its an Y and so on.
Since something less than 33 is clearly a control key I think, (is DEL a control key? Its DEC 127), but anything less than 48 is a symbol I think, but it also has to be more than 32, or do I just implicitly assume if it greater than 32, but less than 48, assume symbol? Annoying how everything seems to inhabit different portions of the ASCII chart.
Here's the code for converting ASCII to HEX, I think decimal might've been easier to work with, but I have no idea how to a) figure out even if I have binary value of the ascii character in a registry somewhere and b) convert it to decimal so since I have this code might as well use it?
;Hex equivalent of characters HEX2CHAR.ASM
;
; Objective: To print the hex equivalent of
; ASCII character code. Demonstrates
; the use of xlat instruction.
; Input: Requests a character from the user.
; Output: Prints the ASCII code of the
; input character in hex.
%include "io.mac"
.DATA
char_prompt db "Please input a character: ",0
out_msg1 db "The ASCII code of '",0
out_msg2 db "' in hex is ",0
query_msg db "Do you want to quit (Y/N): ",0
; translation table: 4-bit binary to hex
hex_table db "0123456789ABCDEF"
.CODE
.STARTUP
read_char:
PutStr char_prompt ; request a char. input
GetCh AL ; read input character
PutStr out_msg1
PutCh AL
PutStr out_msg2
mov AH,AL ; save input character in AH
mov EBX,hex_table; EBX = translation table
shr AL,4 ; move upper 4 bits to lower half
xlatb ; replace AL with hex digit
PutCh AL ; write the first hex digit
mov AL,AH ; restore input character to AL
and AL,0FH ; mask off upper 4 bits
xlatb
PutCh AL ; write the second hex digit
nwln
PutStr query_msg ; query user whether to terminate
GetCh AL ; read response
cmp AL,'Y' ; if response is not 'Y'
jne read_char ; read another character
done: ; otherwise, terminate program
.EXIT
From "Guide to Assembly Programming in Linux".
My query is, if the code converts it to hex, is it actually in memory as hex somewhere? Or is it just displayed as ascii character representation of the hex? That obviously doesn't help me if so.
So my questions are in order:
1.How do I accept user input of a control key.
2. How do I parse ascii so that I have in memory register somewhere which I suppose is a fancy way of saying "variable" the HEX value of the ASCII character I typed in? Which I can then fiddle with and evaluate to display what I need to display?
edit: I think I found a solution, the problem is it doesn't work and I don't know why:
decimal:
mov ebx, 30h ; smallest decimal ASCII
mov edx, key
cmp edx, ebx
jl uppercase
mov ebx, 39h ; test against 9
cmp edx, ebx
jg exit
mov eax, 4
mov ebx, 1
mov ecx, decimalKey
mov edx, decimalLen
int 0x80
It just jumps to "exit" evaluating as "greater than" each time, no matter what I input.

Figured it out finally.
;
; This is assignment 2, it takes key strokes from the user
; and displays whether it is a control key, upper case,
; lower case, a printable symbol, or a decimal.
; By Blayne Elison Bradley, 9688994
; March 4th 2013
segment .data
msg db 'Enter a character: ', 0xA ; text message
len equ $-msg ; length of msg
msg2 db 'Your character is: ' ; text message
len2 equ $-msg2
controlKey: db "Control Key", 10
controlLen: equ $-controlKey
control2Key: db "ControlKey2", 10
control2Len: equ $-control2Key
printableKey: db "Printable", 10
printableLen: equ $-printableKey
printable2Key: db "Printable-2", 10
printable2Len: equ $-printable2Key
printable3Key: db "Printable-3", 10
printable3Len: equ $-printable3Key
printable4Key: db "Printable-4", 10
printable4Len: equ $-printable4Key
decimalKey: db "Decimal", 10
decimalLen: equ $-decimalKey
upperKey: db "Upper Case", 10
upperLen: equ $-upperKey
lowerKey: db "Lower Case", 10
lowerLen: equ $-lowerKey
smallerKey: db "Smaller", 10
smallerLen: equ $-smallerKey
biggerKey: db "Bigger", 10
biggerLen: equ $-biggerKey
segment .bss
;
aChar resb 8 ; reserve 8 bytes for aChar
; I changed the above to 8 and that seems to work with the code below,
; I don't know if its crucial to its execution.
segment .text
global _start
_start:
; ### Code for Outputting a simple Message ###
mov eax, 4 ; select kernal call #4
mov ebx, 1 ; default output device
mov ecx, msg ; second argument; pointer to message
mov edx, len ; third argument: length
int 0x80 ; invoke kernal call to write
mov eax, 3 ; select kernal call #3
mov ebx, 0 ; default input device
mov ecx, aChar ; pointer to aChar'
int 0x80 ; invoke kernal call to read
control: ; is it a control key?
mov al, [aChar] ;
cmp al, 1Fh
jg printable
; Output
mov eax, 4
mov ebx, 1
mov ecx, controlKey
mov edx, controlLen
int 0x80
jmp exit ; because duh
decimal:
mov al, [aChar] ;
cmp al, '9'
jg printable2
; Output
mov eax, 4
mov ebx, 1
mov ecx, decimalKey
mov edx, decimalLen
int 0x80
jmp exit
printable:
mov al, [aChar] ;
cmp al, '/'
jg decimal
; Output
mov eax, 4
mov ebx, 1
mov ecx, controlKey
mov edx, controlLen
int 0x80
jmp exit ; because duh
printable2:
mov al, [aChar] ;
cmp al, '#'
jg uppercase
; Output
mov eax, 4
mov ebx, 1
mov ecx, printable2Key
mov edx, printable2Len
int 0x80
jmp exit ; because duh
uppercase:
mov al, [aChar] ;
cmp al, 'Z'
jg printable3
; Output
mov eax, 4
mov ebx, 1
mov ecx, upperKey
mov edx, upperLen
int 0x80
jmp exit ; because duh
printable3:
mov al, [aChar] ;
cmp al, '`'
jg lowercase
; Output
mov eax, 4
mov ebx, 1
mov ecx, printable3Key
mov edx, printable3Len
int 0x80
jmp exit ; because duh
lowercase:
mov al, [aChar] ;
cmp al, 7Ah
jg printable4
; Output
mov eax, 4
mov ebx, 1
mov ecx, lowerKey
mov edx, lowerLen
int 0x80
jmp exit ; because duh
printable4:
mov al, [aChar] ;
cmp al, '~'
jg control2
; Output
mov eax, 4
mov ebx, 1
mov ecx, printable4Key
mov edx, printable4Len
int 0x80
jmp exit ; because duh
control2: ; is it a control key?
mov al, [aChar] ;
cmp al, 7Fh
jg exit ; beyond range
; Output
mov eax, 4
mov ebx, 1
mov ecx, control2Key
mov edx, control2Len
int 0x80
jmp exit ; because duh
exit:
mov eax, 1
xor ebx, ebx
int 0x80

Related

where to find the implementation of System.Val?

Is there a way to find the implementation of the intrinsic function System.val(..)?
This function works only with unicodeString and I would like to make it working with AnsiString also ... is there any replacement of this function that works with ansiString?
If only decimal digits, and only positive numbers, and no check for overflow (because you know it to never happen), then you can use the following function:
FUNCTION TryAnsiStrToInt(CONST S : AnsiString {EAX} ; OUT Value : Cardinal {EDX} ) : BOOLEAN; ASSEMBLER;
ASM
PUSH ESI
MOV ESI,EAX // ESI = String
XOR ECX,ECX // ECX = Value
CLD
XOR EAX,EAX // Clear upper 24 bits of EAX
#LOOP: LODSB // Load character
OR AL,AL // End-of-String?
JZ #OK
SUB AL,'0' // Convert ASCII to Binary
JB #ERR // Out of range
CMP AL,9
JA #ERR // Out of range
IMUL ECX,10 // ECX:=ECX*10
ADD ECX,EAX // ECX:=ECX+EAX (ie. Value:=Value*10+Digit)
JMP #LOOP // Next character
#ERR: XOR AL,AL // Error: Return FALSE
XOR ECX,ECX // and Value:=0
JMP #OUT
#OK: MOV AL,1 // Success return TRUE
#OUT: MOV [EDX],ECX // and Value
POP ESI
END;
If you have additional requirements (negative numbers, hex numbers, overflow check etc.) you'll need to adapt the function to care for these...

Reading real content of pascal's binary file [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I want to know the real content of binary file.
File was created by Deplhi (FreePascal?) based application.
Filename is FDane.bin
I don't have source code of this app
After disassembling application i see that (part of disassembled code that contain FDane.bin word):
procedure TFrmDroga.ReadLinesFromFile(Sender : TObject);
begin
(*
005F0BB0 55 push ebp
005F0BB1 8BEC mov ebp, esp
005F0BB3 83C4E0 add esp, -$20
005F0BB6 53 push ebx
005F0BB7 56 push esi
005F0BB8 57 push edi
005F0BB9 8945FC mov [ebp-$04], eax
005F0BBC 8D75EF lea esi, [ebp-$11]
005F0BBF 33C0 xor eax, eax
005F0BC1 55 push ebp
005F0BC2 681A135F00 push $005F131A
005F0BC7 64FF30 push dword ptr fs:[eax]
005F0BCA 648920 mov fs:[eax], esp
|
005F0BCD E8DAC4E1FF call 0040D0AC
005F0BD2 DD1D6C936000 fstp qword ptr [$0060936C]
005F0BD8 9B wait
005F0BD9 B201 mov dl, $01
* Reference to class TMemoryStream
|
005F0BDB A144EB4100 mov eax, dword ptr [$0041EB44]
|
005F0BE0 E84735E1FF call 0040412C
005F0BE5 8945F8 mov [ebp-$08], eax
005F0BE8 B201 mov dl, $01
* Reference to class TMemoryStream
|
005F0BEA A144EB4100 mov eax, dword ptr [$0041EB44]
|
005F0BEF E83835E1FF call 0040412C
005F0BF4 8945F4 mov [ebp-$0C], eax
* Possible String Reference to: 'FDane.bin'
|
005F0BF7 BA30135F00 mov edx, $005F1330
005F0BFC 8B45F4 mov eax, [ebp-$0C]
|
005F0BFF E8C834E3FF call 004240CC
005F0C04 6A00 push $00
005F0C06 6A00 push $00
005F0C08 8B45F8 mov eax, [ebp-$08]
|
005F0C0B E8EC2CE3FF call 004238FC
005F0C10 6A00 push $00
005F0C12 6A00 push $00
005F0C14 8B45F4 mov eax, [ebp-$0C]
|
005F0C17 E8E02CE3FF call 004238FC
005F0C1C 8B45F4 mov eax, [ebp-$0C]
005F0C1F 8B10 mov edx, [eax]
005F0C21 FF12 call dword ptr [edx]
005F0C23 85C0 test eax, eax
005F0C25 7E3B jle 005F0C62
005F0C27 8945E8 mov [ebp-$18], eax
005F0C2A BB01000000 mov ebx, $00000001
005F0C2F 8BD6 mov edx, esi
005F0C31 B901000000 mov ecx, $00000001
005F0C36 8B45F4 mov eax, [ebp-$0C]
005F0C39 8B38 mov edi, [eax]
* Possible reference to virtual method TMemoryStream.OFFS_0C
|
005F0C3B FF570C call dword ptr [edi+$0C]
005F0C3E 8BC3 mov eax, ebx
005F0C40 B9C8000000 mov ecx, $000000C8
005F0C45 99 cdq
005F0C46 F7F9 idiv ecx
005F0C48 80C220 add dl, $20
005F0C4B 3016 xor [esi], dl
005F0C4D 8BD6 mov edx, esi
005F0C4F B901000000 mov ecx, $00000001
005F0C54 8B45F8 mov eax, [ebp-$08]
005F0C57 8B38 mov edi, [eax]
* Possible reference to virtual method TMemoryStream.OFFS_10
|
005F0C59 FF5710 call dword ptr [edi+$10]
005F0C5C 43 inc ebx
005F0C5D FF4DE8 dec dword ptr [ebp-$18]
005F0C60 75CD jnz 005F0C2F
005F0C62 6A00 push $00
005F0C64 6A00 push $00
005F0C66 8B45F8 mov eax, [ebp-$08]
|
005F0C69 E88E2CE3FF call 004238FC
005F0C6E 8B45F4 mov eax, [ebp-$0C]
|
005F0C71 E80634E3FF call 0042407C
005F0C76 8B45FC mov eax, [ebp-$04]
* Reference to control TFrmDroga.CDSBrutto : TClientDataSet
|
005F0C79 8B8098040000 mov eax, [eax+$0498]
005F0C7F 8B55F8 mov edx, [ebp-$08]
|
005F0C82 E8A180F0FF call 004F8D28
005F0C87 8B45FC mov eax, [ebp-$04]
* Reference to control TFrmDroga.CDSBrutto : TClientDataSet
|
005F0C8A 8B8098040000 mov eax, [eax+$0498]
After using 'strings FDane.bin | head -n 50' get (this is a part):
&'(1*+,*.
0120456
82s_f\UM%27
6GFFHIJKLB
>6)5?#
,8-05_^^`abcdn*
srrtuvwxq
!"#$%hg,)g
./0323446789:;<s~G#ABCDEFGH
BL{~sm
nbfeVWXZZ[\_^_`abcd;&
hijklmno
2ytDDGDD7GMEN
Re,'
2342678?:;<=>?
EEFGHIJK
EPbdchh
klkj[\]V_`aecdefgh)
lnopqrstu
7ryNILAC2
s"!"#$%&'
7896;<=5?#ABCD
KJKLMNOP
^U`aheg
`jlo`abndefkhijklm
0}qstuvwxy
<w~H
&&'()*+,-./61
z89:*<<>?#ABCDEFGHuJKLMNOPQR
doj[\]L_aaccdefghi$+
mnopqrstu(7qyLK##3C
!"#$%&
Zi +
678/::<8>?#ABC
/IIJKLMNO
YTffgdd
gokn_`aucee`ghijkl
prstuvwx9
;v}MI
b{&%&'()*+
;<=%?AAHCDEFGH
ONOPQRST
RYlklac
\WTSdef{hhj`lmnopq
twxyz{|}
!"#$e
**+,-./0
#ABcDDFHHIJKLMn
QSTUVWXY
V^fPQ^^)YWWXYjklLnnparstuvw8
After 200 lines data changes to this:
MKEUNF/0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWV
5797;
ghijklmnopqrstuvwxyz{|}~
!"#$%&7cFFNF
]AAF]V89:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[G
xyz{|}~
!"#$%&'()*;gBBJZT
a[FO]KRS^<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_x1)3D,
_R T
Vyz{|}~
!"#$%&'()*+,-.
cTDDBXMHW\
t/-')d
)-)3.$;,n
r)t:x8vYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcU5-7H:
!"#$%&'()*+,-./012-da}
qW\I]NJM5*666$f
4,!9:RSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgs,
Z(5856
!"#$%&'()*+,-./0123456:snx
EFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
iyi|v{123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijkg&9$P93?1846xyz{|}~
!"#$%&'()*+,-./0123456789:!f\U
!%;c
?)3'>/k
VWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
ibg#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnoj+"S2'7#+:2:?5^
!"#$%&'()*+,-./0123456789:;<=>2
MNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrsS&
!"#$%&'()*+,-./0123456789:;<=>?#AB_
*6&$'#.l
+#17;!!u
`abcdefghijklmnopqrstuvwxyz{|}~
OVLJ
aikfh
456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwX#
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFf
-)7o
97>=6,9=y
55:D6H&Fijklmnopqrstuvwxyz{|}~
HDOJG_HB
yegenk
456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{N6
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJB
UVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
idolslr'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
!"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNF
YZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
It's looks like there are some character data (I see ASCII up to 127 characters). I'm not a Pascal, Delphi programmer. I know Python, some C and Java. Is it possible to decode ?
Some tips:
The disassembly shows tmemorystream, and then tclientdataset calls. This makes it delphi, and delphi/bcb alone (FreePascal's equivalent is called TBufDataset)
TClientdataset .cds is some proprietary streaming format of a dataset. It might be delphi version dependent. Later (D2010+? rad studio only?) versions come with TClientDataset sources which you could inspect.
Searching for ".cds tclientdataset file format" might also yield something, and hope it doesn't support encryption.

Delphi 6 to Delphi 2007

Just hitting various bricks walls with years worth of code updating, but the current one i cant seem to convert is this
Function Pack (Var Source, Dest; Count : Word) : Word; Assembler;
Asm
Push DS
Mov BX, Count { BX = Count }
Mov AX, Word Ptr Dest
Mov DI, AX
Mov AX, Word Ptr Dest+2 `1`
Mov ES, AX { ES:DI - Dest }
Mov AX, Word Ptr Source
Mov SI, AX
Mov AX, Word Ptr Source+2
Mov DS, AX { DS:SI - Source }
Xor DX, DX { Packed size }
CLD
#Cycle:
Or BX, BX
JZ #End { Done }
LODSB
Mov CX, BX
Cmp CX, 100H
JC #1
Mov CX, 0FFH
#1:
Mov AH, CL
Push ES
Push DI { Save ES:DI before scan }
Push SI
Pop DI
Push DS
Pop ES { ES:DI = DS:SI for scan }
RepE ScaSB
Dec DI
Push DI
Pop SI
Push ES
Pop DS { DS:SI = ES:DI for next }
Pop DI
Pop ES { Restore ES:DI after scan }
Sub AH, CL
Mov CL, AH { CX = repeat count }
Cmp AH, 3
JNC #3 { Repeat count >= 3 }
Cmp AL, RP
JNE #2 { Not a RepeatPrefix byte }
STOSW { Save RP, repeat count < 3 }
Sub BX, CX { Actually count in source }
Add DX, 2 { Actually packed size }
Jmp #Cycle
#2:
Sub BX, CX { Actually count in source }
Add DX, CX { Actually packed size }
Rep STOSB { Save bytes }
Jmp #Cycle
#3:
Sub BX, CX { Actually count in source }
Add DX, 3 { Actually packed size }
Mov CL, AL
Mov AL, RP
STOSW { Save RP, repeat count < 3 }
Mov AL, CL
STOSB { Save repeating byte }
Jmp #Cycle
#End:
Pop DS
Mov AX, DX { Return packed size }
End;
Function UnPack (Var Source, Dest; Count : Word) : Word; Assembler;
Asm
Push DS
Mov BX, Count { BX = Count }
Mov AX, Word Ptr Dest
Mov DI, AX
Mov AX, Word Ptr Dest+2
Mov ES, AX { ES:DI - Dest }
Mov AX, Word Ptr Source
Mov SI, AX
Mov AX, Word Ptr Source+2
Mov DS, AX { DS:SI - Source }
Xor DX, DX { Packed size }
Xor AH, AH
CLD
#Cycle:
Or BX, BX
JZ #End { Done }
LODSB
Dec BX
Cmp AL, RP
JE #1
STOSB
Inc DX
Jmp #Cycle
#1:
LODSB
Mov CX, AX
Add DX, CX
Dec BX
Cmp AL, 3
JNC #2
Mov AL, RP
Rep STOSB
Jmp #Cycle
#2:
LODSB
Dec BX
Rep STOSB
Jmp #Cycle
#End:
Pop DS
Mov AX, DX
End;
[DCC Error] Packer.pas(20): E2107 Operand size mismatch " Mov AX, Word Ptr Dest"
[DCC Error] Packer.pas(22): E2105 Inline assembler syntax error" Mov AX, Word Ptr Dest+2 `1`"
[DCC Error] Packer.pas(24): E2107 Operand size mismatch "Mov AX, Word Ptr Source"
[DCC Error] Packer.pas(87): E2107 Operand size mismatch" Mov AX, Word Ptr Dest"
[DCC Error] Packer.pas(91): E2107 Operand size mismatch " Mov AX, Word Ptr Source"
I spent far to many years on d6, what am i doing wrong?
As a general rule, inline assembly code that compiles in Delphi 6 will compile in later versions too. So no porting should be needed. Indeed, when you attempt to compile this code in Delphi 6, it fails with exactly the same errors as you report from D2007.
You also mention in the comments that you have not been compiling the code in Delphi 6, but have rather been using a compiled .dcu file. Which makes more sense, given that the code in the question does not compile in Delphi 6.
The reason the code does not compile in Delphi 6 is that it is not 32 bit code. It seems to me to be 16 bit code.
Reading between the lines I suspect that the code you have dates from long ago, in the 16 bit age. When the code was moved to 32 bit someone ported the code but left you a .dcu file rather than the source.
You are thus in a pickle. Without knowing what's in this .dcu file what are you to do? Are you even sure that the .dcu file does the same as this 16 bit assembly code? Do you have a functional specification for these functions?
In an ideal world you would know what these functions do and would be able to port them to Pascal. Then you would no longer be tied to assembler code.
If you don't know what these functions do you should find out. I would not trust that your 16 bit assembler matches what your .dcu file does. I would disassemble the .dcu file and port that to Pascal.
If even that's too hard, then the expedient approach is to use Delphi 6 to compile the .dcu file into a DLL. Then you can call these functions from your ported D20007 program. This will work but it leaves you no closer to knowing what your code does.
Yes it is 16 bit register.
Just an idea, maybe declare in your variables example AX as word and AH, AL as byte but you will need to rename them.
example...
Function Example (Var Source, Dest; Count : Word) : Word; Assembler;
var
iAX, iBX, iCX, iDX, iBP, iSI, iDI, iSP: Word;
iAH, iAL, iBH, iBL, iCH, iCL, iDH, iDL : Byte
Asm
Push DS
Mov iBX, Count
Mov iAX, Word Ptr Dest
Mov iDI, iAX
Mov iAX, Word Ptr Dest+2
Mov iES, iAX
.......
P.s
You might have to change "Push DS" and "POP DS" to "PUSH ESI" and "POP ESI"

Delphi - Detect Int64 Overflow Error

In Delphi how can I detect overflow errors for Int64?
For Integers we could do:
type
MyInt = Integer; //Int64
function TryMaxTimes10(out Res: MyInt): boolean;
var
a, b: MyInt;
begin
{$Q+}
try
a := High(MyInt);
b := 10;
Res := a * b; //REF1
Result := True;
except
Result := False;
end;
{$Q-}
end;
For MyInt = Integer, line REF1 gives an exception and so TryMaxTimes10 returns false.
But if we change MyInt to MyInt = Int64, then REF1 does not give an exception and TryMaxTimes10 returns true!
I understand that the help for {$Q+} does not specifically mention Int64: ... {$Q+} state, certain integer arithmetic operations ... are checked for overflow.
QUESTION: So my question is, how can we detect overflow errors for Int64?
(I'm using Delphi 7. Does the same thing happen in newer versions of Delphi?)
This is a known issue. See http://qc.embarcadero.com/wc/qcmain.aspx?d=10185, and the comments Andy wrote at the bottom.
My suggestion would be to create a function (I did not compile nor test this - just an example):
function Foo(A, B : Int64) : Int64;
var bNeg : boolean;
begin
// Do we expect a negative result?
bNeg := ((a < 0) xor (b < 0));
// Get the real result
Result := a * b;
// If the result is wrong, raise an error
if ((Result < 0) xor bNeg) then begin
// Raise EOverFlow
end;
end;
This bug has been fixed in RAD Studio 10.2 Tokyo.
The issue can be found here (but one have to log in with embarcadero account to see it).
Here is correct version of __llmulo by John O'Harrow (licensed under MPL 1.1) shipped with Delphi versions 10.2 and above:
// Param 1(edx:eax), Param 2([esp+8]:[esp+4])
// Result is stored in edx:eax
// O-flag set on exit => result is invalid
// O-flag clear on exit => result is valid
procedure __llmulo();
asm
test edx, edx {Param1-Hi = 0?}
jne ##Large {No, More than one multiply may be needed}
cmp edx, [esp+8] {Param2-Hi = 0?}
jne ##Large {No, More than one multiply may be needed}
mul dword ptr [esp+4] {Only one multiply needed, Set Result}
and eax, eax {Clear Overflow Flag}
ret 8
##Large:
sub esp, 28 {allocate local storage}
mov [esp], ebx {save used registers}
mov [esp+4], esi
mov [esp+8], edi
mov [esp+12], ebp
mov ebx, [esp+32] {Param2-Lo}
mov ecx, [esp+36] {Param2-Hi}
mov esi, edx
mov edi, ecx
sar esi, 31
sar edi, 31
xor eax, esi
xor edx, esi
sub eax, esi
sbb edx, esi {edx:eax (a1:a0) = abs(Param1)}
xor ebx, edi
xor ecx, edi
sub ebx, edi
sbb ecx, edi {ecx:ebx (b1:b0) = abs(Param2)}
xor esi, edi {Sign Flag, 0 if Params have same sign else -1}
mov [esp+16], eax {a0}
mov [esp+20], edx {a1}
mov [esp+24], ecx {b1}
mul ebx {edx:eax (c1:c0) = a0*b0}
xchg ebx, edx {ebx = c1, edx = b0}
mov edi, eax {abs(Result-Lo) = c0}
xor ecx, ecx {Upper 32 bits of 128 bit result}
xor ebp, ebp {Second 32 bits of 128 bit result}
mov eax, [esp+20] {a1}
mul edx {edx:eax (d1:d0) = a1*b0}
add ebx, eax {c1 + d0}
adc ebp, edx {d1 + carry}
adc ecx, 0 {Possible carry into Upper 32 bits}
mov eax, [esp+16] {a0}
mov edx, [esp+24] {b1}
mul edx {edx:eax (e1:e0) = a0*b1}
add ebx, eax {abs(Result-Hi) = c1 + d0 + e0}
adc ebp, edx {d1 + e1 + carry}
adc ecx, 0 {Possible carry into Upper 32 bits}
mov eax, [esp+20] {a1}
mov edx, [esp+24] {b1}
mul edx {edx:eax (f1:f0) = a1*b1}
add ebp, eax {d1 + e1 + f0 + carry}
adc ecx, edx {f1 + carry}
or ecx, ebp {Overflow if ecx <> 0 or ebp <> 0}
jnz ##Overflow
mov edx, ebx {Set abs(Result-Hi)}
mov eax, edi {Set abs(Result-Lo)}
cmp edx, $80000000
jae ##CheckRange {Possible Overflow if edx>=$80000000}
##SetSign:
xor eax, esi {Correct Sign of Result}
xor edx, esi
sub eax, esi
sbb edx, esi
mov ebx, [esp] {restore used registers}
mov esi, [esp+4]
mov edi, [esp+8]
mov ebp, [esp+12]
add esp, 28 {Clears Overflow flag}
ret 8
##CheckRange:
jne ##Overflow {Overflow if edx>$80000000}
test esi, esi {edx=$80000000, Is Sign Flag=0?}
jnz ##SetSign {No, Result is Ok (-MaxInt64)}
##Overflow:
mov ebx, [esp] {restore used registers}
mov esi, [esp+4]
mov edi, [esp+8]
mov ebp, [esp+12]
add esp, 28
mov ecx, $80000000
dec ecx {Set Overflow Flag}
ret 8
end;

Delphi label and asm weirdness?

I written an asm function in Delphi 7 but it transforms my code to something else:
function f(x: Cardinal): Cardinal; register;
label err;
asm
not eax
mov edx,eax
shr edx, 1
and eax, edx
bsf ecx, eax
jz err
mov eax, 1
shl eax, cl
mov edx, eax
add edx, edx
or eax, edx
ret
err:
xor eax, eax
end;
// compiled version
f:
push ebx // !!!
not eax
mov edx,eax
shr edx, 1
and eax, edx
bsf ecx, eax
jz +$0e
mov eax, 1
shl eax, cl
mov edx, eax
add edx, edx
or eax, edx
ret
err:
xor eax, eax
mov eax, ebx // !!!
pop ebx // !!!
ret
// the almost equivalent without asm
function f(x: Cardinal): Cardinal;
var
c: Cardinal;
begin
x := not x;
x := x and x shr 1;
if x <> 0 then
begin
c := bsf(x); // bitscanforward
x := 1 shl c;
Result := x or (x shl 1)
end
else
Result := 0;
end;
Why does it generate push ebx and pop ebx? And why does it do mov eax, ebx?
It seems that it generates the partial stack frame because of the mov eax, ebx.
This simple test generates mov eax, edx but doesn't generate that stack frame:
function asmtest(x: Cardinal): Cardinal; register;
label err;
asm
not eax
and eax, 1
jz err
ret
err:
xor eax, eax
end;
// compiled
asmtest:
not eax
and eax, $01
jz +$01
ret
xor eax, eax
mov eax, edx // !!!
ret
It seems that it has something to do with the label err. If I remove that I don't get the mov eax, * part.
Why does this happen?
Made a bug report on Quality Central.
The practical advice is: do not use label keyword in asm code, use ##-prefixed labels:
function f(x: Cardinal): Cardinal; register;
asm
not eax
mov edx,eax
shr edx, 1
and eax, edx
bsf ecx, eax
jz ##err
mov eax, 1
shl eax, cl
mov edx, eax
add edx, edx
or eax, edx
ret
##err:
xor eax, eax
end;
Updated:
I have not found the bug report in Basm area. It looks like a bug, but I have used BASM for many years and never thought about using label keyword such a way. In fact I never used label keyword in Delphi at all. :)
Well ... back then, in the Delphi-Manual, it used to say something about Compiler-Optimization and thealike-crazyness:
The Compiler generates Stackframes only for nested Routines, for Routines having local Variables and for Routines with Stack-Parameters
The auto-generated Initialization- and Finalizationcode for Routines includes:
PUSH EBP ; If Locals <> 0 or Params <> 0
MOV EBP,ESP ; If Locals <> 0 or Params <> 0
SUB ESP,Locals ; If Locals <> 0
...
MOV ESP,EBP ; If Locals <> 0
POP EBP ; If Locals <> 0 or Params <> 0
RET Params ; Always
If local Variables contain Variants, long Strings or Interfaces they are initialized with Null but aren't finalized afterwards.
Locals is the Size of local Variables, Params the Size of Parameters. If both Locals as well as Params are Null no Init-Code will be generated and the Finalizationcode only contains a RET-Intruction.
Maybe that has got something to do with it all...

Resources