News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

FASMLIB 0.4

Started by vid, December 18, 2006, 08:32:17 PM

Previous topic - Next topic

vid

FASMLIB is multiplatform library for x86 (32 bit) ASM programmers. It is designed to be easy to and powerful (you often have simple and powerful versions of same function). It's purpose is to get programmer rid of annoying routine coding, and to allow to write multiplatform programs easily in assembler. Also it is designed to catch many bugs in code.

There is version for win32 and linux platforms. It has support for FASM and MASM. Support for other platforms and assemblers can be added, just contact me.

Current official release is version 0.4 . Start with unpacking archive and reading file "doc/fasmlib.txt". It will point you further on how to use FASMLIB.

You can find latest version here:
- complete package (170KB)
- without binaries (133KB)

Post any ideas, opinions and questions here

hutch--

Compliments vid,

I had a quick look and this package is very well done.  :U
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

ecube

quote from the readme
"MASM32LIB
---------
I wouldn't list this one, if it wasn't so popular. This not-even-library is just
pure shit. It is extremelly buggy set of random small routines, without any design.
It doesn't even ALLOW you to do things properly... really, hands off this one."

Pretty contradictory wouldn't you say?

hutch--

 :bg

cube,

I excuse people for their inexperience of not knowing the difference between component and object design. The masm32 library is a component library, it leaves object design to people who are better tuned to what they need in their application, not the whims of some library designer.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

vid

nothing personal hutch, but the version of masm32lib i saw was really bad as library. And i was in funny mood when i was writing that, you see  :bdg

I admit i have no idea what terms "object library" and "component library" mean. Maybe you could explain deeper what is masm32lib (if not the thing i understand as "library") and i change my opinion.

Anyway, functions you provide in masm32lib doesn't appear "complete" to me, whether they are part of consistent system or separate component. For example, many many error cases are not taken into account.

japheth

Hm, just curious, why calling something FASMlib which apparently supports FASM *and* MASM.



vid

Flat Assembly Library
has nothing to do with Flat Assembler... in theory  ;)

originally it was meant to be library for FASM, and later I realized it is neatly usable in other assemblers, with linking. I plan support or other assemblers (YASM should be first) too.

hutch--

vid,

I am just about in front of building 2 boxes so i have had the time to have a better look at your library design. I think your idea looks good but you have a common problem in the examples you provided and that is of library granularity which is very easy to solve. Instead of bundling so many procedures together, you get a far better library by doing the extra work of putting every procedure into a seperate module.

It is normal with any language that can use a linker to do this as the linker resolves dependencies between modules and you only ever get the code your application calls and the dependencies, nothing else. Now just as an example, I had a look at the masm example DEC2HEX which builds at 13824 bytes. The following code in MASM builds at 2048 bytes.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    .code

start:
   
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    call main
    inkey
    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

main proc

    LOCAL pbuf  :DWORD
    LOCAL buffer[64]:BYTE

    mov pbuf, ptr$(buffer)

    mov pbuf, input("Enter number here ",62," ")

    invoke dw2hex,rv(atodw,pbuf),pbuf

    print "Your result is "
    print pbuf,13,10

    ret

main endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start


The size difference is nothing to do with your code but rather that you have bundled all of the procedures together instead of allowing the linker to resolve any dependencies from the code that you call. FASM is perfectly capable of producing absolute minimum sized object modules and you could easily duplicate this size with your own library.

I will answer the library object versus component question when I am a bit more awake.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

vid

generally, i don't consider 13kb to be that much so it is worth of effort.

Yes, i agree such binary form would be better for users of binary form. But there is problem with portability you may not have realized. If I want to compile every file to separate .obj file, i must have format settings in every file. Format settings are not portable. So to split platform-independent part from format settings, i would in fact need TWO files for every procedure. When i will add this possibility for ELF, it's three...

I may be able to overcome this somehow, but i don't have sufficent experiences with this. As I understand it, you compile each file to .obj, and then link these .objs to one .lib. When you link with .lib, only files you actually use are defined. This would also get me rid of kernel32.lib dependency. So could someone please provide some info on creating .lib files?

PS: i think "minimal" libc code (input/output) is about 10kb and no one seemed to have problem with that.

PS2: could you please provide me compiled version of that example? I would love to test it's behavior in specific cases

hutch--

I think I understand what you are doing with multi-OS code so it will depend on how much conditional assembly support you have in FASM that can be used on both Linux and Windows platforms. The idea would be to have one file for each procedure but use conditional assembly depending on the target for the code before and after the procedure. In pseudo masm notation, something like this.


IF _win_
  include winstartup.asm
ELSEIF _linux_
  include linuxstart.asm
ENDIF

YourProc proc args etc ....

    ; assembler code here

YourProc endp

IF _win_
  include winend.asm
ELSEIF _linux_
  include linuxend.asm
ENDIF


The idea would be to make a text template and put eaxh procedure into the middle of the template so that the common code was easy to edit while keeping the platform specific code subject to conditional assembly.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

hutch--

Here is a slightly tweaked version of the dec2hex example that demonstrates in a very simple format what the difference between components and objects are in basic library design, the general idea is to have a range of primatives or low level components available that you can construct higher level easier to use objects from. By then being components they are free of much of the higher level protection mechanisms like SEH and other forms of error trapping as it allows the programmer more freedom in design and how and where they place their protection methods.

The problem with the alternatives if the lowest level procedures all have protection mechanisms built into them is that when a more complex object is constructed from such low level components, there is a lot more overhead and the code is larger and slower than without it. It is almost exclusively the case that the programmer constructing the higher level object is better tuned to were an application needs to be protected than at the library construction area.

I have included the binary so it can be disassembled, it has 5 procedures in it, the two conversions, two API based console procedures and one MSVCRT function for halting the console until a key is pressed.


; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    dec2hex PROTO :DWORD

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    LOCAL pbuf  :DWORD          ; buffer pointer
    LOCAL buffer[64]:BYTE       ; 64 byte buffer

    mov pbuf, ptr$(buffer)      ; write buffer address to pointer

  ; -----------------------------------
  ; get the text input from the console
  ; -----------------------------------
    mov pbuf, input("Enter number here ",62," ")

  ; ---------------------------------
  ; display the result at the console
  ; ---------------------------------
    print "Your result is "
    print rv(dec2hex,pbuf),13,10

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

align 4

; ----------------------------------------------
; make a higher level object from two components
; ----------------------------------------------

dec2hex proc pstr:DWORD

    push [esp+4]                ; buffer address as arg for atodw
    call atodw                  ; convert decimal string to a DWORD
    push [esp+4]                ; reuse string address for result
    push eax                    ; return value from atodw
    call dw2hex                 ; write result to original string address
    mov eax, [esp+4]            ; return the original string address
                                ; so it can be used in a macro
    ret 4                       ; balance stack on exit

dec2hex endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start

[attachment deleted by admin]
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

vid

conditional assembly would work, but i don't like i t from design point. I want completely platform-independent sources, and setup format just in one place.

But i might be able to overcome this problem with very nasty FASM trick, i have in my mind :). It's just that i don't know how to create my own .lib file. Don't you happen to have some link about creating (non-import) .lib file?

thanks for your example. here are problems i spotted:
- you completely don't check for case, when user inputs something other than number. You should check this case and warn user.
- reading 80h is not enough. user can prefix number with 100 zeroes, and still it is valid number you should be able to handle
- std input handle is NOT nescessary a console. It can be file aswell (dec2hex.exe <abc.txt).
- you can happen to have no input, in case of EOF (when input is redirected from file, or when typer hits CTRL+Z)
- entered number can be too big to fit in dword


proc text.read.dec2d stream
===========================
desc: reads adecimal number to dword (32 bit). it reads decimal digits (0-9)
and converts them to number, until it reaches non-dec character, or
until number overflows.
args: stream     - handle of stream from which to read
ret: CF set on error, otherwise
EAX = value
note: - before reading, all blank characters are skipped
error: ERR_HANDLE_EOF   - file pointer is on EOF
ERR_OUT_OF_RANGE - value > 4294967295
                   in this case nothing is read from stream.
ERR_NOT_DECIMAL  - first char isn't 0-9
                   in this case, nothing is read from stream.

hutch--

Building the static library is the easy part as long as you produce a collection of compatible object modules that a linker is designed to link into a static library. In the Windows platform Pelle's linker is an excellent tool, any Microsoft linker will link COFF format obj files. From memory the GNU linker LD works fine but I have not used it enough to be familiar with it but for Linux you should have no problems finding an ELF format linker that will do the job.

There was a redundant allocation in the example as the "print" macro allocates a fixed 128 byte buffer with the length being passed to the StdIn procedure so it cannot be broken by user input or text redirection.

The example made no special efort to protect the input from incorrect input data but this is of course the task of the programmer as the bare console input procedure and macro is the wrong place to put any specific test. It is application specific code that should specify what is tested and with an assumed DWORD signed range as is required with the conversion algo there are a number of tests that can be done. Length, then specific characters, 1st must be no greater than ascii "2" etc ... until you determine that the entered number does not exceed the range. Alternatively you could convert the input to QWORD and test if its not out of range that way.

I added a simple length check and this is the result.



............
    .if len(pbuf) > 9
      print "ERROR: Input too long",13,10
      ret
    .endif
............

H:\vidlib\dec2hex>dec2hex < \masm32\include\windows.inc
Enter number here > ERROR: Input too long
Press any key to continue ...


The windows.inc file is over 1 meg but the procedure using ReadFile will only read to the maximum number of characters specified which prevents any buffer overruns.

The slightly tweaked proc looks like this.


main proc

    LOCAL pbuf  :DWORD          ; buffer pointer

  ; -----------------------------------
  ; get the text input from the console
  ; -----------------------------------
    mov pbuf, input("Enter number here ",62," ")

  ; -----------------------------------------------------------
  ; make sure the user does not enter a string that is too long
  ; -----------------------------------------------------------
    .if len(pbuf) > 9
      print "ERROR: Input too long",13,10
      ret
    .endif

  ; ---------------------------------
  ; display the result at the console
  ; ---------------------------------
    print "Your result is "
    print rv(dec2hex,pbuf),13,10

    ret

main endp
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

vid

i believe it's task of conversion procedure to check validity of arguemnt it converts. That is purpose of library, otherwise you would have to check too many things before calling the conversion proc. The checking would be more complicated than conversion itself.

Limiting size of input to 9 is not enough. you are forgetting about leading zeroes. For example "00004294967295" is valid input, but "04294967296" is not. Even if you don't allow leading zeroes in your proc design (pretty weird), then checking number of characters of input is not enough ("4294967295" and "4294967295").

I wonder how did you get the "9" constant. Considering that the readen text also contains 13,10 characters, you limited input to 7 digits... ?

Also your second code contains bug - you are finding size of input with strlen function. But procedure "input" which fills buffers doesn't zero-terminate it. Also, the buffer is stored in stack, eg. it has unpredictable contents. Even if it was initialized to zeroes, using input on same buffer twice could easily produce error. You should use EAX returned from "input"

PS: I wasn't saying there will be buffer overrun when input is redirected from file. I meant to say that you are using Console*** procs, which fail silently in such case, and that you are not prepared for getting EOF on stdin. In fact, you completely ignore the size of readen text (you throw away value of eax after calling "input").

hutch--

We probably differ on what is required but i do it on the basis that the programmer always knows more about what he is writing than I do so i don't impose my views on them.

If you look at the "print" macro, it already trims the trailing 13,10 from the input from the console so if you type 9 characters, thats what you get.

I gather you are not familiar with the macros in masm32, the line of code,


mov pbuf, input("Enter number here ",62," ")


use the masm macro capacity EXITM <eax> so the line is equal to,


mov pbuf, eax


The value in EAX returned from the macro is the offset of the buffer allocated in the "input" macro.

The stack is as predictable as the scope you create the variable within. If you don't need global scope, you allocate a local on the stack like normal, where you put the variable is purely where you need it. If your local procedure storage is unreliable, you have other problems that leave that stack unbalanced.

I don't know where you get the idea of what is returned by the API used in StdIn, for any text typed it always returns,


your_typed_text,13,10,0


The "print" macro calls another proc that trime the tail of the result so it ends up like,


your_typed_text,0


You are right about the tested length, it must be #,###,###,### not including the ",".

The problem with building in such a test for a console input is another user may require a different input, uper case text only, limited ranges of normal ascii characters, mixed case HEX input etc ....

A generic console procedure can be used by any of them where a dedicated one is useless anywhere else. It is very easy to filter input in a text box in GUI mode using the WM_CHAR message but generally with a console you get what is typed and must test it later.

Where we differ is in what target we are pointing code at. If the only market was the low to medium level of C programming, the type of design that encapsulates idiot proof procedures would be appropriate but with assembler programmers who are generally after performance and size of code, slow idiot proof procedures are little use to them. I have only ever catered for assembler rogrammers who will use something if its useful, modify it if its close to useful or simply write their own if they can do it better to suit what they need.

This is why I only ever write components that can be used by low level programmers as I long ago gave up on idiot proof code as there will always be a better idiot.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php