Author Topic: Coding problems  (Read 533 times)

JK

  • Member
  • **
  • Posts: 102
Coding problems
« on: April 24, 2021, 03:47:19 AM »
While this line:
Code: [Select]
and rax, 0ffffffffffffffffhcompiles (in 64 bit), these two:
Code: [Select]
  and rax, 8000000000000000h
  and rax, 0f000000000000000h
fail (error A2084: constant value too large), what is wrong?


in UASM i can code:
Code: [Select]
...macro
local a$
...
a$ catstr ...
invoke myfunc, CSTR(a$), ...
...
endm
which passes a pointer to the string in a$ to myfunc. Unfortunately "CSTR" is not available in ASMC, how to code this in ASMC (passing a pointer of a local (to a macro) string to a procedure)?


Thanks


JK

nidud

  • Member
  • *****
  • Posts: 2147
    • https://github.com/nidud/asmc
Re: Coding problems
« Reply #1 on: April 24, 2021, 04:30:05 AM »
While this line:
Code: [Select]
and rax, 0ffffffffffffffffhcompiles (in 64 bit), these two:
Code: [Select]
  and rax, 8000000000000000h
  and rax, 0f000000000000000h
fail (error A2084: constant value too large), what is wrong?

Immediate values are limited to 32-bit for most instructions except MOV, so you need to use a register there.

    mov rdx, 0f000000000000000h
    and rax, rdx


Quote
in UASM i can code:
Code: [Select]
...macro
local a$
...
a$ catstr ...
invoke myfunc, CSTR(a$), ...
...
endm
which passes a pointer to the string in a$ to myfunc. Unfortunately "CSTR" is not available in ASMC, how to code this in ASMC (passing a pointer of a local (to a macro) string to a procedure)?

You may use text directly in a function call. There's also a @CStr() macro included.

    myfunc( "hello " @CatStr(<!">, <JK, >, <!">) "how's it going\n" )

    *  DS0000 sbyte "hello JK, how's it going",10,0
    *  invoke myfunc, addr DS0000

JK

  • Member
  • **
  • Posts: 102
Re: Coding problems
« Reply #2 on: April 24, 2021, 10:11:47 PM »
Thanks, i see, "0ffffffffffffffffh" works, because it could be seen as "-1".

According to my tests "@CStr" cannot be used in a procedure call directly, you must do e.g. a "lea rax, @CStr("...")" before and then pass rax. Quoted literals don´t work with "INVOKE", your invoke-less call (myfunc("testtext", ...)) is required.

There is yet another problem for me with ASMC: 64bit SEH

Assembled with UASM the following code catches a GPF in 32 and 64 bit, with ASMC it works in 32 bit, but i cannot get it to work in 64 bit:
Code: [Select]
ifdef _WIN64
  option win64:7 ;5
  OPTION STACKBASE : RBP 
else
  .686P
  .model flat, stdcall                      ; 32 bit memory model
  .xmm
  OPTION STACKBASE : EBP 
endif


assume fs:nothing


;option CSTACK:ON
;option WSTRING:ON


include <windows.inc>

includelib kernel32.lib
includelib user32.lib


ifdef _WIN64
  set_seh macro
  endm


  catch_seh macro
    Catch_GPF:

    lea rax, seh_resume
    mov [r8].CONTEXT.Rip_, rax                        ;change the context so execution resumes at label "seh_resume"
    xor rax, rax                                      ;ContinueExecution
    retn

    seh_resume:
  endm


  exit_seh macro
  endm

else
  set_seh macro
    push eax                                          ;save eax
    lea eax, seh_exception                            ;get error handler address
    push eax                                          ;push it

    push dword ptr fs:[0]                             ;save old handler
    mov fs:[0], esp                                   ;install new one
    mov eax, [esp+8]                                  ;restore eax
  endm


  catch_seh macro

  seh_exception:
    mov eax,[esp + 0Ch]                               ;exception  -> get context record
    mov [eax + 0B8h], offset seh_resume               ;set new eip
    xor eax, eax                                      ;exception handled (return eax = 0)
    retn

  seh_resume:
    pop dword ptr FS:[0]                              ;return from exception -> restore old handler
    add esp, 8                                        ;clean up stack
  endm


  exit_seh macro
    pop dword ptr FS:[0]                              ;success -> restore old handler
    add esp, 8                                        ;clean up stack
  endm
endif




_ccount = 0

_atxt macro p:REQ
local tmp$
 
  tmp$ textequ <>
  tmp$ CATSTR <__atxt>, %_ccount
  _ccount = _ccount + 1
 
.data
tmp$ db p, 0
.code 

  exitm <addr tmp$>
endm


.code


ifdef _WIN64
  start proc FRAME:Catch_GPF
else 
  start proc
endif
;***************************************************************************
; test
;***************************************************************************
;.ENDPROLOG
;and rsp, -16


set_seh

  xor eax, eax
  mov eax, [eax]                                      ;gpf



  invoke MessageBoxA, 0, _atxt("test"), _atxt("text"), 0       
;  MessageBoxA(0, _atxt("test"), _atxt("text"), 0)       
;  MessageBoxW(0, "wtest", "wtext", 0)                 ;ASMC option wstring:on
;  invoke MessageBoxA, 0, "test", "text", 0            ;crash 32/64
;  MessageBoxA(0, @CStr("test"), @CStr("text"), 0)     ;argument type mismatch 32/64


exit_seh
  invoke ExitProcess, 0
  ret


catch_seh                                             ;catch exception
  invoke MessageBoxA, 0, _atxt("error"), _atxt("error"), 0

  invoke ExitProcess, 0
  ret

   
start endp


end start

What am i doing wrong? Inserting ".ENDPROLOG" and "and rsp, -16" (for ensuring stack alignment) makes it assemble and work, but then no prologue code at all is created, which is not what i want. I want the prologue code to be the same as without "FRAME:...". How would i do that?


Thanks


JK 

Vortex

  • Member
  • *****
  • Posts: 2556
Re: Coding problems
« Reply #3 on: April 25, 2021, 01:03:59 AM »
Hi JK,

Could you try to use the OFFSET operator & ?

For example \asmc-master\source\test\wininc\Dialog2\test.asm :

Code: [Select]
mov wc.lpszClassName,   &@CStr("WndClass")

nidud

  • Member
  • *****
  • Posts: 2147
    • https://github.com/nidud/asmc
Re: Coding problems
« Reply #4 on: April 25, 2021, 01:21:38 AM »
According to my tests "@CStr" cannot be used in a procedure call directly, you must do e.g. a "lea rax, @CStr("...")" before and then pass rax.

It return a label to the created string so ADDR @CStr("...") will work.

Quote
Quoted literals don´t work with "INVOKE", your invoke-less call (myfunc("testtext", ...)) is required.

It's not so much the INVOKE directive but the bracket followed after myfunc( so Asmc extensions are expanded here ). INVOKE myfunc( "text" ) will also work but the assembler knows that myfunc is a PROC so it's not really needed there. The brackets are for compatibility reasons with “normal” invoke and to remove the difference between a MACRO and PROC, or to equalize the handling of both.

Quote

There is yet another problem for me with ASMC: 64bit SEH

Assembled with UASM the following code catches a GPF in 32 and 64 bit, with ASMC it works in 32 bit, but i cannot get it to work in 64 bit:

I move the include <windows.inc> to the top, changed "start" to "main", and Rip_ to _Rip (I'm using the Asmc include files) and it works here.

Here's a simplified version for 64-bit:

Code: [Select]
include windows.inc

catch proto signo:int_t {
__except:
    mov eax,signo
    .if eax
        lea rax,@F
        mov [r8].CONTEXT._Rip,rax
        xor rax, rax             
        retn
        @@:
        mov eax,1
    .endif
    }

.code

main proc frame:__except

    xor eax,eax
    mov eax,[rax] ;gpf

    MessageBox(0, "test", "text", 0)

    .if catch(0)

        invoke MessageBoxA, 0, addr @CStr("error"), addr @CStr("error"), 0
    .endif
    ExitProcess(0)
    ret

main endp

    end

Quote
I want the prologue code to be the same as without "FRAME:...". How would i do that?

Not sure that's possible as they're interlinked. The FRAME option do not change the prologue code but adds some information to the .xdata segment.
Code: [Select]
public main

extern MessageBoxA: near
extern ExitProcess: near


_text   SEGMENT PARA 'CODE'                             ; section number 1

main    PROC
        sub     rsp, 40                                 ; 0000 _ 48: 83. EC, 28
        xor     eax, eax                                ; 0004 _ 33. C0
        mov     eax, dword ptr [rax]                    ; 0006 _ 8B. 00
        xor     r9d, r9d                                ; 0008 _ 45: 33. C9
        lea     r8, [DS0001]                            ; 000B _ 4C: 8D. 05, 00000000(rel)
        lea     rdx, [DS0000]                           ; 0012 _ 48: 8D. 15, 00000000(rel)
        xor     ecx, ecx                                ; 0019 _ 33. C9
        call    MessageBoxA                             ; 001B _ E8, 00000000(rel)
        xor     ecx, ecx                                ; 0020 _ 33. C9

__except LABEL NEAR
        mov     eax, ecx                                ; 0022 _ 8B. C1
        test    eax, eax                                ; 0024 _ 85. C0
        jz      ?_001                                   ; 0026 _ 74, 17
        lea     rax, [L&_0001]                          ; 0028 _ 48: 8D. 05, 00000000(rel)
        mov     qword ptr [r8+0F8H], rax                ; 002F _ 49: 89. 80, 000000F8
        xor     rax, rax                                ; 0036 _ 48: 33. C0
        ret                                             ; 0039 _ C3

L&_0001 LABEL NEAR
        mov     eax, 1                                  ; 003A _ B8, 00000001
?_001:  test    rax, rax                                ; 003F _ 48: 85. C0
        jz      ?_002                                   ; 0042 _ 74, 18
        xor     r9d, r9d                                ; 0044 _ 45: 33. C9
        lea     r8, [DS0002]                            ; 0047 _ 4C: 8D. 05, 00000000(rel)
        lea     rdx, [DS0002]                           ; 004E _ 48: 8D. 15, 00000000(rel)
        xor     ecx, ecx                                ; 0055 _ 33. C9
        call    MessageBoxA                             ; 0057 _ E8, 00000000(rel)
?_002:  xor     ecx, ecx                                ; 005C _ 33. C9
        call    ExitProcess                             ; 005E _ E8, 00000000(rel)
        add     rsp, 40                                 ; 0063 _ 48: 83. C4, 28
        ret                                             ; 0067 _ C3
main    ENDP

_text   ENDS

_data   SEGMENT PARA 'DATA'                             ; section number 2

DS0000  label byte
        db 74H, 65H, 73H, 74H, 00H                      ; 0000 _ test.

DS0001  label byte
        db 74H, 65H, 78H, 74H, 00H                      ; 0005 _ text.

DS0002  label byte
        db 65H, 72H, 72H, 6FH, 72H, 00H                 ; 000A _ error.

_data   ENDS

.xdata  SEGMENT ALIGN(8) 'CONST'                        ; section number 3

$xdatasym label byte
        db 19H, 04H, 01H, 00H, 04H, 42H, 00H, 00H       ; 0000 _ .....B..
        dd imagerel(__except)                           ; 0008 _ 00000000 (imgrel)
        dd 00000000H                                    ; 000C _ 0

.xdata  ENDS

JK

  • Member
  • **
  • Posts: 102
Re: Coding problems
« Reply #5 on: April 25, 2021, 03:59:55 AM »
Indeed, using your version of "windows.inc" makes the error go away. So there must be some setting inside your includes, which makes the need for ".ENDPROLOG" go away - what is it?

Your version of "windows.inc" implies dependencies i might not want to have all the time. It would be nice to know what exactly causes this error message (missing .ENDPROLOG), i keep getting with other versions, to go away!


Thanks


JK

nidud

  • Member
  • *****
  • Posts: 2147
    • https://github.com/nidud/asmc
Re: Coding problems
« Reply #6 on: April 25, 2021, 08:28:23 AM »
option frame:auto

Quote
This option affects 64-bit only. It allows to make JWasm automatically generate prologues and epilogues for procedures with the FRAME attribute. Thus the code complies to the rules of Win64 SEH (Structured Exception Handling). Syntax is

OPTION FRAME:<AUTO | NOAUTO>

AUTO will enable this feature, NOAUTO (which is default) disables it.

JK

  • Member
  • **
  • Posts: 102
Re: Coding problems
« Reply #7 on: April 25, 2021, 09:13:48 AM »
Quote
option frame:auto

... this finally solves my problem - thanks!

JK

  • Member
  • **
  • Posts: 102
Re: Coding problems
« Reply #8 on: May 05, 2021, 03:12:07 AM »
Trying to convert REAL10 to text: maybe i´m doing something wrong, but some of the results here are not correct:

Code: [Select]
include windows.inc
include fltintrn.inc

.data


;*************************************************************************************
; wrong result:
;*************************************************************************************
g10 real10 -9.000000e+28                              ;_cldcvt wrong ???
;g10 real10 -1.0e23                                    ;wrong by one power of ten
;g10 real10 -1.0e-23                                   ;result = 0
;g10 real10 1.000000e+98                               ;wrong by one power of ten, too many decimal places
;g10 real10 9.000000e+28                               ;wrong by one power of ten, too many decimal places
;g10 real10 -9.000000e+28                              ;wrong by one power of ten, too many decimal places


;*************************************************************************************
; correct result:
;*************************************************************************************
;g10 real10 1.2                                        ;correct
;g10 real10 1.234567890123456789                       ;correct (19 digits)


.code


start proc
;***************************************************************************
; test
;***************************************************************************
local o$[100]:byte


  _cldcvt(addr g10, addr o$, "e", 18, 0)
  OutputDebugStringA(addr o$)


  ExitProcess(0)
start endp


end start



JK

nidud

  • Member
  • *****
  • Posts: 2147
    • https://github.com/nidud/asmc
Re: Coding problems
« Reply #9 on: May 07, 2021, 11:16:18 AM »
Trying to convert REAL10 to text: maybe i´m doing something wrong, but some of the results here are not correct:

These functions is part of the stdio format routines so I haven't really called them directly like this, but after adding floats to the preprocessor I needed to insert a safety pin there to avoid buffer overflow for large numbers. The float format jumps to E formatting on size larger than max digits but this fails as the E and G format needs scaling.

e33 = 9.0e33
e34 = 9.0e34
%echo @CatStr(%e33)
%echo @CatStr(%e34)
end
9000000000000000000000000000000000.0
0.9000000000000000000000000000000e+034

I removed the hack and rewrote some of the code in _flttostr() but it probably needs some more tuning. Note that the ANSI-specified minimum buffer is 509 and the conversion is 128 bit. 512 used in the code, so you need at least this to convert a float. There's no overflow testing, so if the size extend the buffer it just stop parsing and return.

g1 = -9.000000e+28
g2 = -1.0e23
g3 = -1.0e-23
g4 = 1.000000e+98
g5 = 9.000000e+28
g6 = -9.000000e+28

%echo @CatStr(%g1)
%echo @CatStr(%g2)
%echo @CatStr(%g3)
%echo @CatStr(%g4)
%echo @CatStr(%g5)
%echo @CatStr(%g6)
end
-90000000000000000000000000000.0
-100000000000000000000000.0
-0.00000000000000000000001
100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0
90000000000000000000000000000.0
-90000000000000000000000000000.0

So this will overflow:
Code: [Select]
.data
a REAL16 9.0e500
.code
_tmain proc

    _tprintf("%.500llf\n", a)
Output:

900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00000000

But this is in range (9.0e-500):

0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009

JK

  • Member
  • **
  • Posts: 102
Re: Coding problems
« Reply #10 on: May 08, 2021, 12:10:49 AM »
Thanks nidud for the confirmation and explanation!

In a mathematical point of view, it wouldn´t make any sense to display more digits than there are valid digits (in terms of precision), so this:
Quote
real16  1.0e+98
should not be displayed as
Quote
100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0
 
but as:
Quote
1.00000000000000000000000000000000 e+98

This is, because a real16 can represent only a guaranteed maximum of 33 valid decimal places (112 bits of mantissa -> log10(2^112) ~ 33.7). The following place (34) is uncertain (valid or not, depending on the actual number) and all places following the 34. place are in fact nonsense, because numbers with more decimal places just don´t fit into the mantissa (the range is limited to 112 + 1 binary places)

JK

JK

  • Member
  • **
  • Posts: 102
Re: Coding problems
« Reply #11 on: May 08, 2021, 12:47:01 AM »
I just re-tested - sorry to say that, but none of the failing examples (i gave above) works. The results now show the passed number of digits but are still off by one power of ten

nidud

  • Member
  • *****
  • Posts: 2147
    • https://github.com/nidud/asmc
Re: Coding problems
« Reply #12 on: May 08, 2021, 01:18:12 AM »
Thanks nidud for the confirmation and explanation!

In a mathematical point of view, it wouldn´t make any sense to display more digits than there are valid digits (in terms of precision), so this:
Quote
real16  1.0e+98
should not be displayed as
Quote
100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0
 
but as:
Quote
1.00000000000000000000000000000000 e+98

Well, the assembler crops zeros but according to the ANSI-specified format the default precision is 6. The LIBC functions has to follow these rules so the output should be the same for this number as from MSVCTR.DLL.

.data
a REAL16 1.0e98 ; LIBC
...
    printf("%llf\n", a)
100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00000

    movsd xmm0,1.0e98 ; MSVCTR
    printf("%f\n", xmm0)
100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000

So there's a bug there as it is one zero short.

Quote
This is, because a real16 can represent only a guaranteed maximum of 33 valid decimal places (112 bits of mantissa -> log10(2^112) ~ 33.7). The following place (34) is uncertain (valid or not, depending on the actual number) and all places following the 34. place are in fact nonsense, because numbers with more decimal places just don´t fit into the mantissa (the range is limited to 112 + 1 binary places)

There's a difference between decimal places and digits. The number above only have one digit so it's the padding zeros that's blows the buffer. The count of valid digits starts with the first non-zero digit.
Code: [Select]
        mov eax,value
        .if eax
            .for ( ecx = NDIG : ecx : ecx-- )
                xor edx,edx
                div radix
                add dl,'0'
                or  bl,dl ; current digit in BL
                mov [edi+ecx-1],dl
            .endf
            add edi,NDIG
        .else
            mov al,'0'
            mov ecx,NDIG
            rep stosb
        .endif
        add i,NDIG
        .if bl != '0'
            sub bh,NDIG ; max digits in BH
            .break .ifs
        .endif

nidud

  • Member
  • *****
  • Posts: 2147
    • https://github.com/nidud/asmc
Re: Coding problems
« Reply #13 on: May 08, 2021, 01:38:37 AM »
I just re-tested - sorry to say that, but none of the failing examples (i gave above) works. The results now show the passed number of digits but are still off by one power of ten
These are the numbers except from the one above:

-9.000000e+28
-1.0e23     
-1.0e-23     
9.000000e+28
-9.000000e+28

The output from Microsoft(double):

-89999999999999994000000000000.000000
-100000000000000010000000.000000
-0.000000
89999999999999994000000000000.000000
-89999999999999994000000000000.000000

The output from LIBC

-90000000000000000000000000000.00000
-100000000000000000000000.00000
0.000000
90000000000000000000000000000.00000
-90000000000000000000000000000.00000

The only difference I see is the missing zero except the middle one with the correct number of digits but a missing sign(-).

JK

  • Member
  • **
  • Posts: 102
Re: Coding problems
« Reply #14 on: May 08, 2021, 02:10:22 AM »
Ok, then there must be something wrong with my implementation (32 bit code), because my code (g10 real10 -9.000000e+28 .... see post above) results in:
Quote
-0.900000000000000000e+028


To my understanding this number
Quote
100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000
doesn´t have 6 digits of precision but 105 ("1" + 98 x "0" + 6 x "0")