Using Pelle's C run-time library with Masm

Started by Vortex, September 11, 2005, 08:50:22 AM

Previous topic - Next topic

Vortex

Hi friends,

Here a simple example using functions from Pelle's C run-time static library crt.lib :

.386
.model flat,stdcall
option casemap:none

include     \masm32\include\windows.inc
include     \masm32\include\kernel32.inc
include     \masm32\include\user32.inc
include     \masm32\include\masm32.inc

includelib  \masm32\lib\kernel32.lib
includelib  \masm32\lib\user32.lib
includelib  \masm32\lib\masm32.lib
includelib  \pellesc\lib\crt.lib ; Pelle's CRT static library

strcat PROTO C :DWORD,:DWORD
strstr PROTO C :DWORD,:DWORD
strchr PROTO C :DWORD,:DWORD

.data
dest    db 'strcat example : ',0
        db 20 dup(0)
source  db 'Hello my friend',13,10,0
string2 db 'friend',0
crlf    db 13,10,0

.data?
buffer  db 20 dup(?)

.code

start:
invoke strcat,ADDR dest,ADDR source
invoke StdOut,ADDR dest
invoke strstr,ADDR dest,ADDR string2
call   print
invoke strchr,ADDR dest,114 ; look for 'r'
call   print
invoke ExitProcess,0

print   PROC
invoke dw2hex,eax,ADDR buffer
invoke StdOut,ADDR buffer
invoke StdOut,ADDR crlf
ret
print   ENDP

END start

[attachment deleted by admin]

GregL

Vortex,

Nice example. It works fine for me as it is.

If I try to use printf instead of the MASM32 functions, it doesn't work correctly when linking with the static crt.lib. If I change the includelib to use the dynamic pocrt.lib, printf works fine. Any idea why?

I ran into this before and at that time I just decided to use the dynamic lib because it worked. I don't understand why it doesn't work with the static lib.

Here's the code:

.386
.model flat, stdcall
option casemap:none

include     c:\masm32\include\windows.inc
include     c:\masm32\include\kernel32.inc

includelib  c:\masm32\lib\kernel32.lib
includelib  c:\progra~1\pellesc\lib\crt.lib ; Pelle's CRT static library

strcat PROTO C :DWORD,:DWORD
strstr PROTO C :DWORD,:DWORD
strchr PROTO C :DWORD,:DWORD
printf PROTO C :PTR BYTE,:VARARG

CR EQU 13
LF EQU 10

.data

    pStr      DWORD 0
    szDest    BYTE 'strcat example : ', 0, 20 dup(0)
    szSource  BYTE 'Hello my friend', CR, LF, 0
    szString2 BYTE 'friend', 0
    szFormat  BYTE "%u", LF, 0
    szCrLf    BYTE CR, LF, 0

.code
start:

    invoke strcat, ADDR szDest, ADDR szSource
    invoke printf, ADDR szDest
   
    invoke strstr, ADDR szDest, ADDR szString2
    mov pStr, eax
    invoke printf, ADDR szFormat, pStr
   
    invoke strchr, ADDR szDest, 'r'
    mov pStr, eax
    invoke printf, ADDR szFormat, pStr
   
    invoke ExitProcess, 0

END start


Note: I am using polink for the linker.


Vortex

Hi Greg,

Probably, the reason is that printf from crt.lib refers to the start-up code of the static library. I faced the same problem. As you said, you can use the DLL version pocrt.dll  Another solution is to use msvcrt.dll or crtdll.dll to bind dinamically all those functions.

Here is a tiny C run-time startup module demo using pocrt.dll

[attachment deleted by admin]

PellesC

It might work with the static library if you add the following calls (not officially documented, and may change in the future - but I see no reason for it at the moment).

C prototypes:
int __bheapinit(void)
void __ioinit(void)

Something like this...

invoke __bheapinit  ; will return a non-zero value on success, otherwise zero -- for malloc() etc.
test eax,eax
jz byebye
invoke __ioinit  ; will not return anything -- for I/O handles etc.


Pelle

Vortex


GregL

Pelle,

Thanks for that information, it does work. Since it is subject to change, I won't use it in anything important. It's fun to play around with though.  :toothy


PellesC

Thanks. I see no reason for it to change any time soon, probably never, but I don't want to "officially" support it...

Pelle

GregL

Here is an example of using the dynamic version of Pelle's C run-time library (pocrt.dll) in a MASM program. I wrote this program a while back to test the concept. I created the pocrt.inc and pocrt.lib with Hutch's makecimp program. I attached all the files in pocrt.zip.

.586
.MODEL FLAT, stdcall
option casemap:none

include windows.inc

include c:\masm32\include\kernel32.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\masm32.inc
include c:\masm32\pocrt\pocrt.inc

include c:\masm32\macros\macros.asm

includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\masm32.lib
includelib c:\masm32\pocrt\pocrt.lib

Sine       PROTO degrees:PTR REAL8,     sin:PTR REAL8
Cosine     PROTO degrees:PTR REAL8,     cos:PTR REAL8
Tangent    PROTO degrees:PTR REAL8,     tan:PTR REAL8
Arcsine    PROTO sin    :PTR REAL8, degrees:PTR REAL8
Arccosine  PROTO cos    :PTR REAL8, degrees:PTR REAL8
Arctangent PROTO tan    :PTR REAL8, degrees:PTR REAL8
inputR4    PROTO pR4    :PTR REAL4
inputR8    PROTO pR8    :PTR REAL8
inputR10   PROTO pR10   :PTR REAL10

;---------------------------------------
; macros
;---------------------------------------
printf MACRO pszFmt, args:VARARG
    IFB <args>
        IFB <pszFmt>
            invoke pocrt_printf, chr$(13,10)
        ELSE   
            invoke pocrt_printf, pszFmt
        ENDIF
    ELSE
        invoke pocrt_printf, pszFmt, args
    ENDIF   
ENDM   
;---------------------------------------
WaitKey MACRO
    printf chr$(13,10,"Press any key to continue...")
    call wait_key
    printf
ENDM
;---------------------------------------

.DATA

    align 8
    dblDegrees     REAL8   0.0
    dblSine        REAL8   0.0
    dblCosine      REAL8   0.0
    dblTangent     REAL8   0.0
           
.CODE

start:

    printf chr$("Enter angle in degrees: ")
    invoke inputR8,  ADDR dblDegrees
       
    printf
    printf chr$("Angle                 = %9.6lf degrees",13, 10), dblDegrees
                   
    invoke Sine, ADDR dblDegrees, ADDR dblSine
    invoke Cosine, ADDR dblDegrees, ADDR dblCosine
    invoke Tangent, ADDR dblDegrees, ADDR dblTangent
       
    printf
    printf chr$("Sine(%.1lf)            = %8.6lf", 13, 10), dblDegrees, dblSine
    printf chr$("Cosine(%.1lf)          = %8.6lf", 13, 10), dblDegrees, dblCosine
    printf chr$("Tangent(%.1lf)         = %8.6lf", 13, 10), dblDegrees, dblTangent
    printf
           
    invoke Arcsine, ADDR dblSine, ADDR dblDegrees
    printf chr$("Arcsine(%8.6lf)     = %9.6lf degrees", 13, 10), dblSine, dblDegrees
   
    invoke Arccosine, ADDR dblCosine, ADDR dblDegrees
    printf chr$("Arccosine(%8.6lf)   = %9.6lf degrees", 13, 10), dblCosine, dblDegrees
   
    invoke Arctangent, ADDR dblTangent, ADDR dblDegrees
    printf chr$("Arctangent(%8.6lf)  = %9.6lf degrees", 13, 10), dblTangent, dblDegrees
               
    WaitKey
       
    invoke ExitProcess, 0

;======================================================
; procedures
;======================================================
Sine PROC degrees:PTR REAL8, sin:PTR REAL8
    LOCAL radians:REAL8
    IFNDEF DtoR
        .CONST
            DtoR    REAL10 0.017453292519943295769  ;(Pi / 180.0)
    ENDIF   
    .CODE
        mov     eax, degrees
        finit
        fld     REAL8 PTR [eax]
        fld     DtoR
        fmul
        fstp    radians
        fwait
        invoke  pocrt_sin, radians    ;result in ST(0)
        mov     eax, sin
        fstp    REAL8 PTR [eax]
        fwait
        ret
Sine ENDP
;======================================================
Cosine PROC degrees:PTR REAL8, cos:PTR REAL8
    LOCAL radians:REAL8
    IFNDEF DtoR
        .CONST
            DtoR    REAL10 0.017453292519943295769  ;(Pi / 180.0)
    ENDIF   
    .CODE
        mov     eax, degrees
        finit
        fld     REAL8 PTR [eax]
        fld     DtoR
        fmul
        fstp    radians
        fwait
        invoke  pocrt_cos, radians    ;result in ST(0)
        mov     eax, cos
        fstp    REAL8 PTR [eax]
        fwait
        ret
Cosine ENDP
;======================================================
Tangent PROC degrees:PTR REAL8, tan:PTR REAL8
    LOCAL radians:REAL8
    IFNDEF DtoR
        .CONST
            DtoR    REAL10 0.017453292519943295769  ;(Pi / 180.0)
    ENDIF   
    .CODE
        mov     eax, degrees
        finit
        fld     REAL8 PTR [eax]
        fld     DtoR
        fmul
        fstp    radians
        fwait
        invoke  pocrt_tan, radians    ;result in ST(0)
        mov     eax, tan
        fstp    REAL8 PTR [eax]
        fwait
        ret
Tangent ENDP
;======================================================
Arcsine PROC sin:PTR REAL8, degrees:PTR REAL8
    IFNDEF RtoD
        .CONST
            RtoD    REAL10 57.295779513082320876798  ;(180.0 / Pi)
    ENDIF       
    .CODE
        mov     eax, sin
        invoke  pocrt_asin, REAL8 PTR [eax]    ;result in ST(0)
        mov     eax, degrees
        fld     RtoD
        fmul
        fstp    REAL8 PTR [eax]
        fwait
        ret
Arcsine ENDP
;======================================================
Arccosine PROC cos:PTR REAL8, degrees:PTR REAL8
    IFNDEF RtoD
        .CONST
            RtoD    REAL10 57.295779513082320876798  ;(180.0 / Pi)
    ENDIF   
    .CODE
        mov     eax, cos
        invoke  pocrt_acos, REAL8 PTR [eax]    ;result in ST(0)
        mov     eax, degrees
        fld     RtoD
        fmul
        fstp    REAL8 PTR [eax]
        fwait
        ret
Arccosine ENDP
;======================================================
Arctangent PROC tan:PTR REAL8, degrees:PTR REAL8
    IFNDEF RtoD
        .CONST
            RtoD    REAL10 57.295779513082320876798  ;(180.0 / Pi)
    ENDIF   
    .CODE
        mov     eax, tan
        invoke  pocrt_atan, REAL8 PTR [eax]    ;result in ST(0)
        mov     eax, degrees
        fld     RtoD
        fmul
        fstp    REAL8 PTR [eax]
        fwait
        ret
Arctangent ENDP
;======================================================
inputR4 PROC pR4:PTR REAL4
    invoke pocrt_scanf, chr$("%f"), pR4
    ret
inputR4 ENDP
;======================================================
inputR8 PROC pR8:PTR REAL8
    invoke pocrt_scanf, chr$("%lf"), pR8
    ret
inputR8 ENDP
;======================================================
inputR10 PROC pR10:PTR REAL10
    LOCAL r8:REAL8
    invoke pocrt_scanf, chr$("%lf"), ADDR r8
    mov eax, pR10
    finit
    fld r8
    fstp REAL10 PTR [eax]
    ret
inputR10 ENDP
;======================================================
end start



[attachment deleted by admin]

Vortex

Using lib2inc, I created all the function prototypes from crt.lib :
lib2inc \pellesc\lib\crt.lib

After replacing all the StdOut functions with printf, here is the new listing :

.386
.model flat,stdcall
option casemap:none

include     \masm32\include\windows.inc
include     \masm32\include\kernel32.inc
include     \masm32\include\user32.inc
include     \masm32\include\masm32.inc
include     crt.inc

includelib  \masm32\lib\kernel32.lib
includelib  \masm32\lib\user32.lib
includelib  \masm32\lib\masm32.lib
includelib  \pellesc\lib\crt.lib ; Pelle's CRT static library

.data
dest        db 'strcat example : ',0
            db 20 dup(0)
source      db 'Hello my friend',13,10,0
string2     db 'friend',0
template1   db '%s',13,10,0
template2   db '%X',13,10,0

.data?
buffer  db 20 dup(?)

.code

start:

    invoke  __bheapinit
    test    eax,eax
    jz      finish
    invoke  __ioinit
    invoke  strcat,ADDR dest,ADDR source
    invoke  printf,ADDR template1,ADDR dest
    invoke  strstr,ADDR dest,ADDR string2
    invoke  printf,ADDR template2,eax
    invoke  strchr,ADDR dest,114 ; look for 'r'
    invoke  printf,ADDR template2,eax

finish:

    invoke ExitProcess,0

END start

[attachment deleted by admin]

Vortex

Same example assembled with POASM

[attachment deleted by admin]