OASML 2.0 is the second version of the Open-source Assembly Library
which is a huge update to the first version.
The OASML 2.0 library is intended to simplify your task of programming
in the 16-bit Real-mode architecture of CPU by implementing hundreds
of procedures and describing every single line of the code with
comments so that you can understand what really is happening.

Below is the list of the major updates and bug fixes in OASML 2.0 and
also the important features of the library:

  ? OASML 2.0 now supports access to the XMS memory with easy-to-use
    procedures. You need not create any structures or anything to be
    able to work with XMS. All you have to do is to allocate, deallocate
    write to, read from and etc. The procedures in the unit
    handle the structures for you in the stack.

  ? OASML 2.0, although based on 16-bit architecture, simulates
    32-bit AND 64-bit values. This means that you can write 32/64 bit
    values to the screen, read 32/64 bit numerical values from the
    screen, convert these values to hex, binary, octal and vice versa.

  ? A QWORD unit is added to the library which allows 64-bit numerical
    values to be manipulated through the simulation of 64-bit instructions.

  ? The unit now contains 48 procedures including Length-Dependent
    procedures that allow the maximum size of the source/destination to
    be specified in order to avoid buffer overflows.

  ? A new unit is added to the library called which
    allows simple operations to be carried out on the graphics mode
    of 320.200. Operations include drawing horizontal/vertical lines,
    filling the screen, changing pallets and etc.

  ? A unit is added to the library which facilitates
    direct access to the Text-Mode Video Memory. Using this unit
    you can write directly to the Video Memory of the Text Mode
    of 80.25 characters.

  ? The unit of the library now contains 39 procedures
    that work with absolute values, logarithms, consines, sines,
    conversion from angles in degrees to radians and etd.

  ? The unit, short form of Miscellaneous, now contains
    more procedures dealing with various computations.

  ? Length-dependent procedures are also added to the unit
    to allow you specify the maximum length of the buffer in cases
    that the procedure needs to copy bytes to the destination. Other
    procedures are also added to this unit such as .

  ? The unit now contains 45 procedures with a lot of new
    additions such as the procedure which
    allows a 64-bit QWORD value to be printed to the screen as
    a hexadecimal value including the zeros to the left.

  ? The , and the procedures
    had a minor bug in OASML 1.0 that is now fixed in OASMl 2.0.

  ? The procedure used to remove its parameter
    from the stack which is now fixed.

  ? The , , , and the
    procedures are now optimized for both speed and size.

  ? A lot of string-related procedures now would not destroy the AX
    register. These procedures are , , ,
    and etc.

  ? Some procedures used to be incompatible with 8086 instructions,
    such as the procedure. This problem is fixed
    in OASMl 2.0.
  ? For a complete list of updates, you can view the file
    in the OASML 2.0 package. The file lists the bugs
    that are fixed in this version of the library.

More information: You can visit THIS page.
Download OASML 2.0: You can download OASML 2.0 HERE.

I'd be glad to hear your suggestions and/or comments.
Posted on 2007-01-12 03:59:16 by XCHG
The unit now contains 48 procedures including Length-Dependent
    procedures that allow the maximum size of the source/destination to
    be specified in order to avoid buffer overflows.
congrats. is there some general behavior in case some of buffer overflows? what happens? Designing this took me some while, so i wonder about yours ;)

also, why the 8086 support? do you think there will be usage for that?
Posted on 2007-01-12 06:12:12 by vid
Hello vid,

I thought of a return value in case of the buffer overflows and generally, length-dependent procedures because normal string procedures in the library do not return a value and just do what they are supposed to do except when a return value is expected from them like the ?StrGetChar? procedure. In length-dependent procedures, I used the AX register to indicate information related to the operation that the procedure has done. For example, if either the source or the destination lengths are zero, AX will be set to zero and the procedure will terminate immediately. That is the best method I could come up with. Perhaps there are other ways around it, too.

The AX register will also be set to the number of bytes copied to the destination string including or excluding the null-terminator. I have written the default behavior of each of these procedures in their comment block. I?d be glad to hear your insights on this.
Posted on 2007-01-13 00:08:34 by XCHG
Description : Concatenates the maximum number of AX bytes from the source string
                  to the destination string and would terminate the destination
                  string upon success. The AX register will then be equal to the
                  length of the final string. See note(s).

i think you didn't really catch the point with this design. Primary purpose is to make sure, that DESTINATION string never overflows it's buffer size. This is hard with your current design, because you need to know current size of dest string, to set AX to such value it won't overflow.

Now, yours AX can prevent read overflow of source string, but preventing overflow of dest string is much more important.

for my ideas of design, see FASMLIBs string routines: http://fasmlib.flatassembler.net/src/str.inc. Shortly: with EVERY string, you must also pass it's buffer size.
Posted on 2007-01-17 00:23:57 by vid
I was talking about procedures such as that accept the number of bytes to copy and not the maximum size of the buffer. In this case, I think it would be irrational to ask the user to provide the length of both the source and the destination. It would be like "I have 3 bytes of space in my destination buffer but please copy as many as 10 bytes".

I have implemented the "Both src and dest length" mechanism on procedures such as "lStrScanForChars" with parameters like this:

    Parameter(s) :
      WORD Param1 = Source string's offset.
      WORD Param2 = Source string's maximum length.
      WORD Param3 = Destination string's offset.
      WORD Param4 = Destination string's maximum length.
      WORD Param5 = Number of bytes to copy.
      WORD Param6 = Starting index inside the source string.

So should we really have a procedure like:

int lStrCopy (char* Destination, int DestinationLength, char* Source, int SourceLength)

or should it be:

int lStrCopy (char* Destination, int DestinationMaxLen, char* Source);

Thank you for your response vid.

Posted on 2007-01-17 02:14:22 by XCHG

In this case, I think it would be irrational to ask the user to provide the length of both the source and the destination. It would be like "I have 3 bytes of space in my destination buffer but please copy as many as 10 bytes".

It's not irrational once you consider typical usage scenarios.

Without the buffer-size parameter, you always need to make sure you never pass a too large value to the function. Not very surprisingly, people often forget this - a google search for "buffer overflow" gives you two million reasons to add checking code (okay, 1.8mil, and the overflows are of various nature, but you get the drift).

Adding a "SourceBufferLength" parameter seems a bit over-paranoid, it would take some pretty extreme situations to cause, say, a pagefault, or informating leaking. But if you want to be 100% safe...

Anyway, for a 16bit library, "who cares" - 16bit x86 is not going to be used for anything critical, it's not going to be interfaced to a network, etc etc etc.
Posted on 2007-01-17 03:27:24 by f0dder
f0dder: i did pretty new approach in FASMLIB that makes usage of source buffer length useful in some cases. here are basic rules:

- length of buffer is passed for EVERY string (thus you also get some generality and don't need to browse docs so much)
- whenever string buffer overflows, chars in buffer are filled as they were if buffer was long enough, and ERR_BUFFER_FULL error is returned.
- in case of ERR_BUFFER_FULL, destination string is NOT zero terminated. That is because i await every error is catched with FASMLIB (jc error... soooo easy)
- if source string is not zero-terminated within buffer, no error is thrown, but only chars in buffer are actually used.

this allows user to use same string libraries on non-zero-terminated string buffers (like section name in PE header), just by ignoring ERR_BUFFER_FULL.

Also to read from such buffer, you don't even have to catch and ignore errors. No errors are returned in such case.

Many people may dislike not terminating buffer with zero, but you are protected twice:
1. error is returned in such case. you can end with non-zero-terminated string only when you decide to ignore ERR_BUFFER_FULL.
2. still, when working with string using FASMLIB routines, you pass string length, so these won't ever overflow buffer.

I found this solution to be most flexible, and still pretty safe.
Posted on 2007-01-17 05:49:35 by vid
Hmmm... ignoring errors is generally a pretty bad idea. IMHO things like PE header sections should be handled by special-case code.

I also prefer not to modify output buffer in the case it's too small - it can be dangerous trying to process partial information.
Posted on 2007-01-17 08:29:47 by f0dder
it's not simple "ignoring errors" :D
it is ignoring ERR_BUFFER_FULL only, which notifies you that only first part of buffer is filled, and buffer is not zero-terminated.

I also prefer not to modify output buffer in the case it's too small - it can be dangerous trying to process partial information.
Every time partial information is stored, you get error. You work with partial information only if you decide to specifically ignore this error. In case of error buffer could be left as-is aswell, this way is just the procedure more powerful for very special cases (like PE header section name).

I just designed functions so that they are fine for everyday use, but also make it possible for you to use them for more special cases, so you don't need another set of procedures (like you proposed). You just use them in sligthly different matter
Posted on 2007-01-17 12:46:17 by vid
How about the speed? How many clock cycles approximately would it take to copy a null-terminated string of 65536 bytes into another using specific lengths? I performed a benchmark on Delphi's default StrCopy function which does not have length checking on either the source or the destination and for the source and the destination strings aligned on a DWORD boundary it took ~301714 clock cycles for the first run.

Window's lstrcpy function took ~207709 clock cycles for the same source and destination at the first run. I am wondering how many clock cycles it would take to copy a string into another with both the source and the destination buffer's length checks. Window's default lstrcpyn which checks the destination buffer's length only took ~566910 clock cycle for the same source and string which is unacceptable.
Posted on 2007-01-18 02:07:00 by XCHG
more realistic case would be 65536 copies of 20byte strings.
i haven't benchmarked it yet, but procs are generaly not fast.

it's hard to compare, since my procs do little more than typical strcpy() or strcat(), because of that buffer checking.
Posted on 2007-01-18 04:56:50 by vid