<-- /BYTE* / Borland Turbo Assembler (TASM) Unofficial Changelist 
Borland Turbo Assembler (TASM) Unofficial Changelist

NOTE: If you notice any incorrect version information here or you have information to add, please use the Contact Form!

The Rise of Turbo Assembler
Turbo Assembler, abbreviated TASM, was made by Borland International in 1988 to compete with Microsoft's Macro Assembler (MASM). TASM 1.0 was released 1 year after the highly successful introduction of their Turbo C compiler and associated integrated development environment (IDE) and about 6 months after Microsoft released MASM 5.1. One of the reasons TASM became popular was because it was bundled with Turbo C and later Borland C/C++ products.

Borland's compilers were more popular than Microsoft's equivalent compilers in the late 80s and early 90s, especially to the hobbyist developers that could not afford Microsoft's hefty price tag. Borland products quickly received a reputation for development tools that were cheaper, faster and more efficient than Microsoft's as well as other competitors. However, their success was driven largely due to Borland's products being bundled with an IDE: something the world was ready for and computers at the time were just becoming powerful enough to run. The IDE allowed editing of source code, compiling, linking, debugging and well as organizing the project/build settings (command line options), all without leaving the program's environment. Microsoft's compilers, like most of the compilers of the day, consisted of diverse command line tools. Editing source code, building and debugging was left to different tools that had to be invoked separately. To have one program house all the tools (or at least automatically invoke the appropriate tool when needed) proved to be an instant success.

Although Turbo Assembler never had its own IDE (nor did MASM), TASM 1.0 dealt a large blow to MASM with the introduction of "IDEAL" Mode. IDEAL mode was designed to compensate for the shortcomings of MASM, specifically the syntax used in MASM 5.x. If you didn't need or want the alternative IDEAL mode syntax, and had only MASM code, TASM was guaranteed to assemble the past 3 versions of MASM's code (4.0, 5.0, 5.1) without any (or few) modifications. MASM was described as a "complicated beast" to deal with due to the problems with data type handling and its numerous ad-hoc assembler directives. In comparison with MASM, TASM's IDEAL mode simplified the source code, had stricter type-checking and introduced better structured data handling. By version 3.0, the VERSION directive was introduced to make TASM even more compatible with specific versions of MASM as well as older versions of Turbo Assembler. It was with this feature that TASM was well known for being "more MASM-compatible than MASM itself". TASM's emergence onto the market was likely the single most-important motivation for Microsoft to fix their outdated MASM syntax.

One other feature-set unique to TASM is its object-oriented capabilities added in version 3.0. MASM never added object-oriented capabilities. My guess is that Microsoft might not have believed there were enough assembly-language programmers that cared about an object-oriented assembler.

The Decline of Turbo Assembler
Despite early success, popularity for TASM waned in the mid to late 90s largely because developers had begun to shift away from assembler programming in general, utilizing easier and quicker programming languages that hid the sometimes "ugly" details of coding directly to specific processors. However, it is my opinion that popularity specifically for TASM (over MASM) declined for two reasons:
  1. TASM never fully supported the MASM 6.x Syntax:

    TASM entered the market supporting all of MASM's syntaxes and strange behaviors (known by TASM as "QUIRKS"). To offer developers the no-risk option to switch to a cheaper and faster assembler without having to change their source code was huge. Prior to MASM 6.0, TASM was clearly superior not only in speed, but in syntax and affordability. Borland included some rather humorous remarks in the TASM User's Guides regarding MASM, especially in the explanation for features such as "QUIRKS mode" and the "NOSMART" directive to enable building questionable MASM source files:

    If you are having trouble assembling a program with Turbo Assembler, you might try using the QUIRKS directive (which enables potentially troublesome features of MASM)
    For maximum compatibility with MASM, you should use the NOSMART directive along with QUIRKS mode.

    With all of MASM's problems, Microsoft eventually did deliver a better assembler in version 6.0. This was about 2 months after the release of TASM version 2.5. In reality, the combined MASM 6.0 and 6.1 releases finally brought MASM up to the level TASM has been at for years as it addressed all the problems that TASM's IDEAL mode had "fixed". Many people had the opinion that MASM was finally equivalent to TASM, give or take some modifications to the to syntaxes. And, 4 years later with the release of 6.11d (MASM's last DOS assembler), the MASM 6.x series had stabilized into a rock-solid assembler that was faster with a more elegant syntax. TASM still did not support any of its new syntax.

    Borland may have felt that because their assembler had been superior in the past, there was nothing left for them to prove; or perhaps they wanted to stop trying to be like MASM? Whatever they were thinking, something changed their mind. Nearly 5 years later with the release of TASM 5.0, the MASM 6.x syntax was finally supported. But, because TASM's implementation of the syntax never approached the near-100% compatibility they had become famous for in the past, this feature may have been too little, too late. MASM compatibility remained for the pre-6.x syntaxes, but those were becoming obsolete.

    MASM compatibility was important for TASM because Microsoft had an advantage over its competitors. Microsoft made the operating systems everyone was developing applications for. Anything Microsoft released (whether copied from competitors, or bought from them) would be considered "standard" by a large portion of the market. People would want to learn and develop in Microsoft's standard syntax simply because it came from Microsoft. To underestimate the importance of supporting MASM syntax to its fullest was a mistake on Borland's part.
  2. Borland's Employee Mass-Exodus:
    Within months after releasing the TASM 5.0r patch, Borland filed a lawsuit against Microsoft for "systematically recruiting Borland developers in an attempt to eliminate the company as a competitor" as quoted from the May 12, 1997 Network World article (below). According to the complaint, Microsoft's recruiting efforts began back in 1994. A ComputerWorld article (below) quoted Borland CEO, Delbert Yocam as saying, "...Microsoft lured away Borland employees with hefty signing bonuses, and recruited them by sending limousines to Borland headquarters and taking them out to lunch." This was likely the fatal blow from which Borland would never recover. You could almost speculate that Borland lost the developer(s) who maintained TASM to Microsoft, just as Borland's Chief Engineer, Anders_Hejlsberg (inventor of Turbo Pascal and chief architect for Delphi) also defected to Microsoft in 1996.

    Article: Borland fights big brain suck
    NetworkWorld - May 12, 1997
    Microsoft steals borland employees #1 Microsoft steals borland employees #2
    Article: Borland says Microsoft raided staff
    ComputerWorld - May 12, 1997
    Borland says Microsoft raided staff

    In all fairness, I'll mention that prior to Microsoft hiring all of Borland's employees, Borland did indeed hire an ex-Microsoft Languages manager, Rob Dickerson, in 1988. Microsoft attempted, but failed to enforce their non-complete policy in court and both sides settled out of court with Dickerson ultimately being able to work for Borland. The article goes on to say, "As part of the settlement, both companies agreed they will not hire an employee from each other for the next six months." Microsoft gave Borland about 6 years before it began hiring its employees away.

    Article: Microsoft-Borland scuffle could open exit door
    ComputerWorld - Jan 11, 1988
    Borland Hires Microsoft Employees

    Although Borland may have drawn first-blood by hiring a manager that quit Microsoft, it is quite a different thing to have Microsoft systematically "gut" all of Borland's employees. This is one example of many anti-competitive practices Microsoft was involved with, eventually catching the attention of the US Department of Justice.

    Article: Justice Department versus Microsoft
    NetworkWorld - May 25, 1998
    DOJ vs Microsoft #1 DOJ vs Microsoft #2

Although TASM 5.0 now supported some of the high-level language features present in the MASM 6.1 syntax, the changes needed to assemble a MASM 6.x source file with TASM 5.0 were slightly more involved than people were interested in performing. That didn't mean TASM 5.0 was necessarily a "dud", but many expressed disappointment. Tomcat's Win32Asm Document said the following:

When Borland announced the brand new TASM 5.0 in March 96, I rushed my order, thinking it would solve most of the remaining problems I had with MASM (like TASM had done in the past). Unfortunately, it turned out to be different: TASM, that once used to be more compatible with MASM than MASM itself, now fails to fully support a number of the new MASM capabilities that appeared with MASM 6.10. Several of these being features that make programming to Win32 much easier, I regretfully had to go the MASM way rather than the Borland one.

Also around this time, Borland seemed to be going through an identity crisis. It decided to move away from low-level development tools (including TASM and Borland C++), shifting focus to what it referred to as "Enterprise" applications. This seemed to translate to database technology combined with rapid application development (WYSIWYG) tools. This was around the time C++Builder was born from Delphi. At least the database focus would seem to place Borland in a good position to aid the larger businesses that were forced to upgrade their "ancient" database technology in response to imminent Y2K problems. Perhaps even more importantly, "Enterprise" level databases were not already a market dominated by Microsoft.

As part of the new company focus, Borland changed its name to Inprise on April 29, 1998. As the company's CEO Delbert Yocam explained, the new name meant “invoking the enterprise”. Apparently the enterprise had not been “invoked” enough, as the name was changed back to Borland less than 3 years later in January of 2001.

About one year earlier (approximately February 2000), things may have started looking up to the Borland/Inprise employees as C++Builder 5 was released with some embedded anti-Microsoft easter-eggs. One might gather from looking at the images that they were not only fighting a war with Microsoft, but they were also winning thanks to a creature known as "Borzilla" representing Borland/Inprise. The employees were obviously fans of the vintage arcade classic "Rampage" where you control Godzilla-looking creatures to destroy cities. The most notable images are the Linux & Borzilla vs. Seattle (where Microsoft is located) and Borzilla eating Bill Gates. The remainder of the images and easter-egg details can be found in the TASM 5.3 section.

Anti-Microsoft Easter Eggs in C++Builder 5
C++Builder 5 Easter Eggs - Rampage Linux vs Seattle (Microsoft) C++Builder 5 Easter Eggs - Rampage Eating Bill Gates

After years of obvious struggling, Borland's development tools division (named CodeGear at the time) was sold off to Embarcadero Technologies on May 7, 2008 shortly before Borland was acquired by Micro Focus on May 6, 2009.

As for the future of TASM, 5.0 was the last version distributed as a stand-alone retail product. Shortly after, the 5.0r patch was released to make TASM compatible with C++Builder. The future for TASM32.EXE would be to stick it in a "bin" directory with a plethora of other command line tools bundled in the C++Builder Professional (and greater) editions. TASM 5.2b was bundled with C++Builder 3 just before Borland changed its name to Inprise. 5.2b finalized the the MMX instruction set, added some Pentium Pro support and fixed some bugs. TASM 5.2 would be released 1 year later with C++Builder 4, adding the remainder of the Pentium Pro instructions and marking the last version of TASM with new features. TASM 5.3 was bundled with C++Builder 5 and fixed a few more bugs likely marking the last version of TASM with any changes. Beyond this, Turbo Assembler was essentially a defunct product. In 2006, C++Builder and Delphi were merged into the same development environment called Borland Developer Studio (later renamed to RAD Studio around the time Borland sold its CodeGear tools division to Embarcadero). All of these development environments, including the free trial versions, bundle a copy of TASM 5.4 which seemed to only have name and version number changes.

The lack of keeping TASM current sent a clear message to the developer community that TASM was no longer a product being actively maintained and developed. Despite this, many stuck with TASM well into the turn of the century. But, with Microsoft supplying MASM for free with every version of Visual C++ released starting with the 6.0 Processor Pack, there became little reason not to use the actively developed and supported MASM with the latest processor support. If you don't require support for Ideal Mode, the assembler development community seems to recommend MASM the most as it supports all current instruction sets and its still being maintained by Microsoft. Even the most die hard TASM developers eventually switched to MASM or another assembler that was being actively maintained.

Despite TASM not keeping up with the times, there does appear to be a maintained list list of open/closed bugs that can be viewed on Embarcadero's QualityCentral site. Unfortunately, (as of 2015) these only include two SSE feature requests, one for SSE (released by Intel for the Pentium III in 1999) and SSE3 (released by Intel in 2004) which have yet to be implemented. The other open bug is in regards to a nested structure's member names clashing with the names of the structures themselves. As you can tell, not a whole lot of activity going on here.

Other Compatible Assemblers
It appears that there is only one true Turbo Assembler clone - a free product named Lazy Assembler (LZASM). Lazy Assembler also supports instruction sets never available with TASM: SSE, SSE2, SSE3 (PNI), SSE4 (MNI), and 3DNow! Pro. The last version came out in 2007 and the original website is gone. The project appears to be dead.

In 1999 Paradigm Systems released Paradigm Assembler (PASM), known by many as a Turbo Assembler clone based upon Borland's version 5.0. According to a 2010 blog on MASM Forum, Paradigm Systems licensed Turbo Assembler 5.0 from Borland/Inprise and bundled it with the Paradigm C++ product. PASM was reverse-engineered just enough to reveal it was nothing more than a loader with TASM32.EXE embedded. Upon execution, it was claimed that it would extract TASM32.EXE to a temporary directory and execute it to perform the actual assembler work.

I have been able to verify this claim: PASM32.EXE first calls a function within their own ADMIN.DLL (as all of their utilities do) to ensure Paradigm's proprietary dongle exists; upon success a file named PASM32.DLL is extracted (with system and hidden attributes applied); PASM32.DLL, not really a DLL but internally an EXE, is then launched to do the assembler work, and then the file is deleted. This PASM32.DLL is actually the TASM32.EXE claimed (albeit modified). At the very least, the string literals have been changed to "Paradigm Assembler", however like TASM32, the TURBOASSEMBLER constant continues to exist in the module's DATA segment. The file weighs in at 178k which is less than TASM 5.0 and 5.0r (at 180k and 184k respectively), so Paradigm likely received from Borland a full build environment from which to fully tailor the TASM codebase to suit their purpose. Had Paradigm actually authored the assembler, it is likely the dongle protection would have been built directly into the EXE rather than the roundabout method they employed to extract the real tool.

It should come as no surprise that the Paradigm Assembler manual is close to an exact copy of the Borland Turbo Assembler 5.0 User's Guide, literally word-for-word with minor modifications. The only differences appear to be that they replaced all occurrences of "Turbo Assembler" with "Paradigm Assembler", "Borland C++" with "Paradigm C++", swapped out the sample in chapter #1 with their own and removed the introduction at the front of the book. Because no good quality digital reproduction of the official Turbo Assembler 5.0 User's Guide was available at the time, the Paradigm Assembler PDF manual, known for its small size and searchability became distributed among the Internet for TASM developers and can still be found on various sites today. The easiest place to find it is on the Phat Code website; either from their Lazy Assembler page or embedded within the TASM 5.0 download on its Turbo Assembler 5 page. A "clone" in the context of computer software generally means a different program that acts like or emulates the behavior of another to a high degree. Paradigm Assembler is not a TASM clone because it internally uses TASM and is therefore not a different program. All of this might lead one to believe Paradigm C++ might also be a licensed copy/modification of Borland's C++.

As a side-note, a complete and fully searchable PDF copy of the official Turbo Assembler 5.0 User's Guide is now available on archive.org (about 14MB), courtesy of the bitsavers.org scan collection.

Although not a clone, the free and actively maintained Netwide Assembler (NASM) for 16/32/64-bit development supporting Windows, Unix/Linux, and even DOS and OS/2 has the -t command-line option for "TASM Compatibility Mode". It is described in the NASM Documentation as:

NASM includes a limited form of compatibility with Borland's TASM. When NASM's -t option is used, the following changes are made:
  • local labels may be prefixed with @@ instead of .
  • size override is supported within brackets. In TASM compatible mode, a size override inside square brackets changes the size of the operand, and not the address type of the operand as it does in NASM syntax. E.g. mov eax,[DWORD val] is valid syntax in TASM compatibility mode. Note that you lose the ability to override the default address type for the instruction.
  • unprefixed forms of some directives supported (arg, elif, else, endif, if, ifdef, ifdifi, ifndef, include, local)
Turbo Assembler Printed Manuals
With each new version, the Turbo Assembler official documentation provided less and less information. This trend was similar with MASM. It was almost as if as the product matured, the new features were added on an ad-hoc basis known to the large companies in the industry (such as low level hardware, chip and BIOS manufacturers) that may have requested the "features", but time and resources in properly documenting this information to the public was not devoted. It is likely that an assembler being such a low-level "backend" tool just didn't have the public visibility to justify the means. Observe the declining number of pages in the TASM printed manuals throughout the years, even as each new version had more features than the previous one:

TASM 1.0 User's Guide / 1988 / 572 pages
TASM 2.0 User's Guide / 1990 / 503 pages (69 pages dropped)
TASM 3.0 User's Guide / 1991 / 381 pages (122 pages dropped)
TASM 4.0 User's Guide / 1993 / 347 pages (34 pages dropped)
TASM 5.0 User's Guide / 1996 / 290 pages (57 pages dropped)

Therefore, the purpose of this page is to document what changed between each version even as official information became more and more limited. Before changes stopped being documented altogether in the post-Borland years, the Turbo Assembler manuals usually just added a chapter or section explaining the new features but didn't mention that the feature(s) were "new". Starting with the 3.0 User's Guide, an appendix was added at the end with keywords new to each version up to the current manual's version. As I leveraged this information as part of building the changelist information, I found that Borland was extremely sloppy in preparing these lists. If you have access to one of these manuals and you compare it to the changelist information compiled on this site, you'll find the information in the manuals grossly underestimated what was actually added to each version! Not only were the lists incomplete with every version, many keywords were incorrectly placed and some of the keywords were flat out wrong, either because no such keyword actually existed or a couple instances where multiple keywords were "glued" together as one keyword! No only that, but many "new" keywords in these lists were never described in the manual! It was also sad to note that the last User's Guide (version 5.0) was missing updated information for 32-bit Windows application development.

An Official Yet Unofficial IDE
Many may be surprised to learn that the version 7 Turbo Pascal and Borland Pascal IDE's, possibly the Borland C++ IDE too, had such a surprising level of TASM integration, some may have considered them the unofficial IDE for TASM. Unofficial because a program's entry point still required a language other than assembly. Beyond simply spawning TASM during the build process, these IDE's included some valuable source and debugging features. For example, when TASM reports build errors, the IDE positions the cursor at the first error line in the source code, with the option to visit all lines containing errors. When single-step debugging finds its way into a linked TASM module, the corresponding .ASM source appears and current assembly line hilighted. Assembly-level debugging features included tracing, setting breakpoints (both absolute and conditional), variable watch, register inspection, and even spawning TASM to re-assemble during debugging (if the source was changed).

Courtesy Jim from oldskool.org for this section's information and screenshots below:

Pascal program loading
external OBJ
(note the $L directive)
IDE: external TASM OBJ
In-line assembler,
single-stepping up to
external object call
IDE: In-line ASM
During Trace,
IDE loads
TASM source
IDE: Trae loads TASM source

Turbo Assembler books
Besides the official Borland manuals, there were not as many books dedicated to TASM. Books dedicated to MASM however were more plentiful. Most of the these TASM books were written pre-version 3.0 and even then there were only a handful. The Turbo Assembler Bible was one of them, designed for TASM 2.0. Because a lot has changed since TASM 2.0 (and other assemblers since the TASM 2.0 release in 1990) it is considered primitive even for 16-bit programming. This combined with the fact that the bulk of the book is reference material that can be found elsewhere, this book's primary significance is historical (and it has a neat pirate picture on the cover!).

Although these pre-version 3.0 books may delve a bit into TASM's IDEAL mode syntax, they didn't cover the object-oriented features unique to TASM that were added in version 3.0. But, there was one book that came out in 1989 followed by a second (and final) edition published 1995 that will forever be known as the definitive guide to TASM. Although it only covers through version 4.0, the book, "Mastering Turbo Assembler" delves into just about every TASM detail known. This book was written by Tom Swan, one of the best computer book authors of the 80s-early 90s computer era (also the author of the widely successful and definitive "Masting Turbo Pascal x.x" series). The assembler code shown in the book was almost exclusively in IDEAL mode and it is one of the only books that covers the object oriented features of TASM. In fact, this tome of 908 pages is a better reference than the official Borland manuals themselves, especially since Swan leveraged the assistance of Borland employees to write the book! Although the 2nd edition only covered TASM through version 4.0, the TASM 5.x changes that came after it was published only made TASM more MASM-compatible which wouldn't have been covered by this book anyway. Therefore, this book continues to be relevant to the TASM distributed by Embarcadero today.

Mastering Turbo Assembler
(1st Edition) © 1989, Tom Swan
695 Pages
Mastering Turbo Assembler 1st Edition Book - Front Cover Mastering Turbo Assembler 1st Edition Book - Back Cover
Mastering Turbo Assembler
(2nd Edition) © 1995, Tom Swan
908 Pages
Mastering Turbo Assembler 2nd Edition Book - Front Cover Mastering Turbo Assembler 2nd Edition Book - Front Cover
The Waite Group's
Turbo Assembler Bible

© 1991, Gary Syck / 717 Pages
The Waite Group's Turbo Assembler Bible - Front Cover The Waite Group's Turbo Assembler Bible - Back Cover

The only other book I know of that deals with the features of modern (post-3.0) TASM is "Windows Assembly Language and Systems Programming" 2nd edition by Barry Kauler. While this book goes into details about the differences between MASM and TASM, Kauler prefers TASM over MASM and therefore most of the code in the book follows suit. Kauler also devotes an entire chapter (about 42 pages) delving into the object-oriented nature of programming in assembly language which you really won't find in any other book. Most books (typically in the field of reverse engineering) will discuss how certain snippets of object-oriented C++ code disassembles into corresponding assembly language, but Kauler illustrates a unique view. He shows how one might use an object oriented assembler like TASM to implement objects in a pure assembly language without any constraints that would be placed upon a compiler (such where the VTABLE might go: common to the class or per object instance). Although he does use TASM-specific keywords such as the TABLE directive, his code for the most part is fairly generic assembler that could be easily ported to MASM or other assemblers. Besides the TASM specifics, I highly recommend this book despite the large focus on 16-bit Windows 3.1 and Windows 95 programming. There is little doubt that 16-bit programming is dead in the world, but I think it would do any serious assembly language programmer some good to have general knowledge of the convoluted nature of 16-bit hardware implementation. 16-bit x86 programming, a scheme born out of limited resources and backwards compatibility is harder than 32-bit programming and takes some serious skill to master. 16-bit code is not completely gone as it is still used in BIOS and low level processes such as bootloaders. This is true even on PCs that will ultimately boot a 32-bit or even 64-bit protected mode operating system. In my opinion, this book gave the clearest and most detailed explanation of what is really going on with the processor and memory from when you hit the power switch, to when DOS loads (Pre Windows 2000/XP that is), to when Windows loads, the different processor modes (real mode, virtual 86 mode, protected mode), what descriptors are and their layouts, as well as how segments address memory with 20-bits, etc. For those that use the 32-bit FLAT model for assembly language programs, there are 16-bit artifacts in that architecture and its good to know these roots! Additionally, this is also one of the only books I know of that explains the inner workings of how you can drop from user mode (ring 3) in a protected mode program down to kernel mode (ring 0) using call-gates.

Windows Assembly Language and Systems Programming
16- and 32-Bit Low-Level Programming for the PC and Windows
(2nd Edition) © 1997, Barry Kauler / 419 Pages
Windows Assembly Language and Systems Programming 2nd Edition Book - Front Cover Windows Assembly Language and Systems Programming 2nd Edition Book - Back Cover

The books described above (as well as the Turbo Assembler software itself) are unofficially classified by the world as obsolete software for obsolete operating systems with no economic value. Soon, they may be sought-after vintage collectibles, but not while there are such large numbers remaining in circulation. I say grab them while you can off of Amazon or eBay for pennies on the dollar because these books are generally cheaper than the cost to ship them. If you don't mind paying a little more, you can usually get them in near-mint condition!

Turbo Assembler Versioning
It is interesting to note that embedded within the binary executable of each version of TASM is the following string:
??version equ xx*256+yy
This appears to be the internal definition for TASM's ??version macro, utilizing internal major and minor version numbers xx and yy respectively. This formula stores the major version in the upper byte and the minor version in the lower byte of what was likely intended as a 16-bit version number. This explains why the reported ??version numbers (shown in the table below) are generally large powers of two.

I have attempted obtain the most complete version information for Borland's TASM throughout its history using official information where available and falling back to bits and pieces from other sources when information is limited. This includes printed manuals, readme's and other information shipping with the product, or official websites. When appropriate, opinions and hearsay are also included (and noted as such), as this helps develop a clearer picture of how the product impacted those who used it.

Changelist for this document
    2018-12-08     * added section (at top) "An Official Yet Unofficial IDE"

    2017-03-20     * added TASM version 2.01; reworked version 2.02 in light of the previously unknown 2.01 version
                     causing some features originally attributed to 2.02 to move to 2.01

                   * found and added new undocumented error message to TASM 2.02 I previously missed

    2016-09-15     * added C++Builder 5 and 6 easter-egg images to the TASM 5.3 image group; also referenced 2 of the images
                     and added a blurb about the anti-Microsoft easter-eggs in the intro's history section; updated official
                     file date for TASM 5.3 to reflect confirmed date on C++Builder 5 CD.

    2016-09-08     * revisions made to TASM 5.2 and TASM 5.3 summaries now that I could confirm the contents of C++Builder 5
                     and 6; pictures of C++Builder 5 and 6 were added to the TASM 5.3 section

Jump to TASM Version Info / 20 Versions Listed

VersionCopyrightRuns UnderMain Program Date/File/Size??versionVersion Decoded
TASM 1.0198808/29/1988 01:00amTASM.EXE97,876 bytes / 96 k256xx=1 yy=0
TASM 1.01198905/02/1989 01:01amTASM.EXE95,910 bytes / 94 k257xx=1 yy=1
TASM 2.0199005/07/1990 02:00amTASM.EXE105,881 bytes / 103 k512xx=2 yy=0
TASM 2.01199010/29/1990 02:01amTASM.EXE105,651 bytes / 103 k513xx=2 yy=1
TASM 2.02199003/13/1991 03:02amTASM.EXE71,283 bytes / 70 k514xx=2 yy=2
TASM 2.5199102/13/1991 02:00amTASM.EXE106,521 bytes / 104 k517xx=2 yy=5
TASM 2.511991TASM.EXE106,521 bytes / 104 k517xx=2 yy=5
TASM 3.0199111/11/1991 04:00amTASM.EXE115,471 bytes / 113 k768xx=3 yy=0
TASM 3.1199206/10/1992 03:10amTASM.EXE129,266 bytes / 126 k778xx=3 yy=10
TASM 3.2i199210/01/1992 07:00amTASM.EXE133,698 bytes / 131 k788xx=3 yy=20
TASM 3.2199203/09/1993 07:01amTASM.EXE133,580 bytes / 130 k788xx=3 yy=20
TASM 4.0199312/01/1993 04:00amTASM32.EXE163,840 bytes / 160 k1024xx=4 yy=0
TASM 4.1199602/15/1994 06:33pmTASM32.EXE163,840 bytes / 160 k1034xx=4 yy=10
TASM 5.0199602/21/1996 05:00amTASM32.EXE184,320 bytes / 180 k1280xx=5 yy=0
TASM 5.0r199602/05/1997 01:00amTASM32.EXE188,416 bytes / 184 k1280xx=5 yy=0
TASM 5.2b199602/09/1998 03:00amtasm32.exe188,416 bytes / 184 k1282xx=5 yy=2
TASM 5.2199901/27/1999 04:00amTASM32.EXE188,416 bytes / 184 k1282xx=5 yy=2
TASM 5.3200001/30/2000 10:00pmTASM32.EXE188,416 bytes / 184 k1283xx=5 yy=3
TASM 5.4200901/14/2009 12:03pmtasm32.exe188,416 bytes / 184 k1284xx=5 yy=4
TASM 5.4201012/07/2013 04:55pmtasm32.exe194,936 bytes / 190 k1284xx=5 yy=4

Jump to Keyword Version Info

Types / Allocation
Macros / Procedures
CALL (high-level)2.0
Scope / Module
Equates / Assignment
Repeat Blocks
Conditional Assembly
Conditional Control Flow/Flags
Conditional Error
Listing Control
Console Output/Echoing
Instructions and Warning Classes
Warning Classes
ALN - Segment alignment
ASS - Assuming segment is 16-bit
BRK - Brackets needed
GTP - Global type doesn't match symbol type2.0
ICG - Inefficient code generation
INT - INT 3 generation3.1
LCO - Location counter overflow
MCP - MASM compatibility pass2.0
OPI - Open IF conditional
OPP - Open procedure
OPS - Open segment
OVF - Arithmetic overflow
PDC - Pass-dependent construction
PQK - Assuming constant for [const] warning
PRO - Write-to-memory in protected mode using CS
RES - Reserved word warning
TPI - Borland Pascal illegal warning
UNI - For turning off uninitialized segment warning3.1
Models and Languages
Calling Conventions
ASSEMBLER1.x (renamed to NOLANGUAGE in 2.0)
Memory Models
Model Modifiers
Segment Attributes
Version Identifiers
Symbols and Registers
Text Equates
MASM and Ideal-Mode Equivalents
MASM Mode Directives
.TYPE **
Equivalent Ideal-Mode Directives
(none) *
* TASM defaults to collecting segments in sequential order
** .TYPE and SYMTYPE are operators. All other keywords in the table above are directives.

Not Officially Documented
Undocumented Keywords / Possible Features?
FNLDENV (u)4.0
FNRSTOR (u)4.0
OBJDEF (u)3.0
OBJEND (u)3.0
PROCBEG (u)3.0
PROCEND (u)3.0

TASM 1.0 © 1988 Borland International [Command Line]
TASM.EXE97,876 bytes (96k)md5=95874a9aab76526ab263839f4f769da2date=8/29/1988 1:00am
??version reports: 256
Retail Price: $149.95

Borland releases their first version of Turbo Assembler (TASM) the month of September 1988 (bundled with the first version of Turbo Debugger) for $149.95. Borland also simultaneously releases Turbo Pascal 5.0 and Turbo C 2.0. View the README.

The first version of TASM supported the Intel 8086, 80186, 80286 and 80386 processors along with the 8087, 80287 and 80387 numeric coprocessors. The 80386 (i386) processor, released by Intel in October of 1985, was the latest processor at the time.

Intel 80386 Processor

I have seen a distribution of TASM 1.0 with the file dates: 10/31/1988 1:00am. Despite this being nearly two months after the release date according to the article below, I believe the file dates might still legitimately represent one in a series of multiple releases of the same version. This is in part due to the updated documentation files that maintained the same general content, but reworded some sentences and fixed grammatical errors.

  • IBM PC XT, AT, PS/2 or compatible computer
  • MS-DOS 2.0 or later
  • At least 256K of memory

Article: Borland
goes for
Code Pros
August 29, 1988
Borland Goes for Code Pros
Borland Languages
Advertisement w/
TASM 1.0
September 9, 1988
Borland Languages Ad, 1988
Article: Turbo
Debugger and Turbo
Assembler 1.0
September 12, 1988
Turbo Debugger and Assembler 1.0
Article: Borland
Unveils New
Programmers Tools
September 22, 1988
Borland Unveils New Tools
Article: TASM, Debugger:
Innovative Software,
Unworthy Documentation
PC Magazine
November 15, 1988
Turbo Assembler, Debugger: Innovative Software, Unworthy Documentation

The Gloves are Off!”
Shortly after the release of TASM 1.0, Microsoft reacts with a white paper describing incompatibilities between MASM and TASM.

Article: Borland Disputes Microsoft's Assembler Benchmark Claim
InfoWorld - February 6, 1989
Borland Disputes Microsoft's Assembler Benchmark Claim

TASM 1.0
TASM 1.0 Box TASM 1.0 Manuals #1 TASM 1.0 Manuals #2

TASM 1.01 © 1988, 1989 Borland International [Command Line]
TASM.EXE95,910 bytes (94k)md5=c3a968f96540074489d208a934e27a37date=5/2/1989 1:01am
??version reports: 257

The changelist below was derived from the README and binary analysis.

  • Listing files generated with /LA will now contain the mnemonics for the opcodes inserted as a result of the use of high level language directives. The listing is changed only for things that actually generate code such as the first instruction of a PROC with arguments. The listing of things such as .MODEL, .CODE, and other instructions that do not actually generate any code will not be changed. /LA also overrides other directives that turn off listing. If certain parts of listing need to be supressed use /L instead of /LA.
  • If a string is defined with a DB instruction, and a comma is the last thing on the line, a null byte will be assumed at the end of the string. A warning will be generated. For example:
    db 'ABCDEF',
    will generate the following, with a warning "Trailing null assumed"
    41 42 43 44 45 46 00
  • If a structure instance does not have any initializer specified the "Trailing null assumed" warning will be generated. No extra zeros are placed in the emitted code.
  • Segment alignment and padding now match MASM.
  • Confusion about certain features of TYPE used in IDEAL mode should be cleared up by the following addition to the manual:
       Function  Returns a number indicating the size of a symbol
                 (Masm mode), or returns the type of a  symbol 
                 (Ideal mode)
       Mode      MASM, Ideal
       Syntax    Masm mode: TYPE <expression>
                 Ideal mode:  TYPE <symbol>
       Remarks   Masm mode:
                 (Keep discussion as exists now)
                 Ideal mode:
                     TYPE is used to get the type of an
                     existing symbol.  In Ideal mode, this
                     operation can only be used where a type
                     specifier is needed.
       Example   Masm mode:
                     (Keep discussion as exists now)
                 Ideal mode:
                     bvar    db 1    ;Byte storage.
                     tempvr  dt ?    ;Scratch area.
                     mov     [bvar],0 ;Clear byte variable.
                     mov     [type bvar ptr tempvr],0
                                      ;Clear scratch area of 
                                      ;same size.
                                      ;Equivalent to 'BYTE PTR'.
  • TED.ASM from PCMAGNET will now assemble and link properly. Be sure to use the /t switch with TLINK to produce a .COM file.
  • Existence of ">" character within a string passed to IFB macro directive causes TASM 1.0 to report that extra characters are on line. This will now be handled without an error if QUIRKS directive is used. All characters past the embedded ">" will be ignored.
  • Colons within label names passed to IFDEF macro directive are now ignored if QUIRKS directive is used. All characters past the colon are ignored.
  • In tiny model programs, all registers should be pointing to the same DGROUP. If unwanted SS: overrides occur when referencing variables in the DGROUP, use the statement ASSUME SS:NOTHING to causes CS: overrides to be used.
  • [bytepointer.com edit] The PUBLICDLL directive appears in the binary and it assembles without error, although the feature is not officially available until version 2.0.

TASM 2.0 © 1988, 1990 Borland International [Command Line]
TASM.EXE105,881 bytes (103k)md5=b68a63d6a94672910d4149fad4c18f00date=5/7/1990 2:00am
??version reports: 512
Retail Price: $149.95

This version of TASM introduced support for the 80486 (i486) processor released by Intel in April of 1989.

Intel 80486 Processor

Additionally, the console output during assembly added the line "Passes:" above "Remaining memory:". The status lines shown below would not change until version 5.0:
Turbo Assembler  Version 2.0  Copyright (c) 1988, 1990 Borland International

Assembling file:   ver_dos.ASM
Error messages:    None
Warning messages:  None
Passes:            1
Remaining memory:  475k
The changelist below is an abbreviated form from the README, the corresponding UPDATE.DOC and binary analysis. Keywords revealed by binary analysis NOT present in any available changelist documentation are denoted by a "(u)". The keywords that are completely undocumented as to their function, even in future documentation, are listed in the possible undocumented features section at the bottom.

  • PUBLICDLL directive:
    The PUBLICDLL directive lets you define program labels and procedures to be dynamic link entry points as well as publicizing them to your other modules, which allows you to build dynamic link libraries in assembly code.
    [bytepointer.com edit] Support unofficially available in version 1.01, but first documented here. This is an IDEAL mode only directive.
  • Multiple pass capability - NOP removal:
    Turbo Assembler 2.0 can pass over your source code more than once either for compatibility with some of MASM's pass-dependent constructions or to remove NOP instructions that were added to the code because of forward references. This feature is enabled by the command-line switch /m#, where # is the maximum number of passes allowed. Turbo Assembler automatically assesses the need to perform extra passes up to the maximum that you specify.
  • CALL extensions:
    The CALL instruction has been extended in Turbo Assembler to allow high-level language routines to be called in a language-independent manner. Any CALL instruction can now specify a language and an argument list for the routine being called. Turbo Assembler automatically generates the necessary stack setup and cleanup code required to pass the arguments to a high-level routine written in the specified language.
  • PUSH, POP instruction extensions:
    The PUSH and POP instructions have been extended in Turbo Assembler to allow more than one argument to appear in a single PUSH or POP instruction. For example,
        push ax dx       ;equivalent to PUSH AX then PUSH DX
        pop  dx ax       ;equivalent to POP DX then POP AX
    In addition, the PUSH instruction allows constant arguments even when generating code for the 8086 processor. Such instructions are replaced in the object code by a 10-byte sequence that simulates the 80186/286/386 PUSH immediate value instruction.
  • COMM extension:
    The COMM directive has been extended to allow the array element size and the array element count to be selected independently of each other for FAR communal variables. This supports Turbo C++'s inline code generation, and can be used advantageously by a native assembly language programmer.
  • Generalized line-continuation character:
    In TASM 2.0, a line-continuation feature has been added that works in TASM's Ideal mode and is available even when the MASM 5.1 mode is off. A backslash (\) can be placed almost anywhere as a line-continuation character. It cannot be used to break up strings or identifiers. Its meaning is "read the next line in at this point and continue processing." It can thus be used in a natural way without losing the ability to comment each line as desired.
  • Language-specific procedures, extrns, publics:
    TASM 2.0 allows procedures, publics, extrns, and calls to be overridden with a language specifier. This causes wide flexibility in writing assembler code that interfaces with multiple language models. The MODEL statement has also been extended.
    [bytepointer.com edit] Binary analysis suggests that the language modifier keyword "ASSEMBLER" was renamed to "NOLANGUAGE" in this version.
  • New MODEL language modifier - WINDOWS:
        .MODEL large,windows pascal
        foo proc
        arg abc:word,def:word
                xor ax,ax       ;Generates FAR WINDOWS PASCAL sequences.
        foo proc normal c
        arg ghi:word,jkl:word
                xor ax,ax       ;Generates FAR NORMAL C sequences.
    [bytepointer.com edit] This modifier was an important feature for 16-bit Windows programming. It allowed the declaration of a high-level FAR PROC for a 16-bit Windows callback function; something never supported by MASM (without the use of additional includes). The User's Guide describes the modifiers as follows:

    [The language modifier of the model directive is used] to specify additional prolog and epilog code when you write procedures for Windows, or for the Borland Overlay loader.

    Barry Kauler's book, "Windows Assembly Language and Systems Programming" describes the WINDOWS qualifier as:

    The WINDOWS qualifier takes care of generation of the special prolog and epilog required for a [16-bit Windows 3.x] callback function.
    ...only applies to 16-bit TASM applications.

    The WINDOWS qualifier was never supported in MASM. To get the same result in MASM, one had to include CMACROS.INC and PROLOGUE.INC and enable the OPTION PROLOGUE/EPILOGUE features. For reference, Barry Kauler's book provided the prologue and epilogue code sequences the WINDOWS language modifier causes the assembler to generate:
        push ds    ;prologue for Windows 16-bit callback function
        pop ax
        inc  bp
        push bp
        mov  bp,sp
        push ds
        mov  ds,ax
        dec  bp    ;epilog for Windows 16-bit callback function
        dec  bp
        mov  sp,bp
        pop  ds
        pop  bp
        dec  bp
        ret  10
  • Virtual segments:
    A new keyword VIRTUAL has been added to the SEGMENT statement. VIRTUAL defines a special kind of segment that will be treated as a common area and attached to another segment at link time.
  • QASM Compatibility Additions:
    TASM 2.0 has new and modified directives to support source code for QASM:

    These commands generate startup code for the particular model in effect at the time. These also define the near label @@Startup and cause the END statement at the end of the module to generate the equivalent of 'END @@Startup'. Note that only the 'STARTUPCODE' directive is available in IDEAL mode.

    .MODEL and MODEL
    It is now possible to select a third field in the .MODEL statement to specify the stack association with DGROUP: NEARSTACK or FARSTACK. For example, .MODEL SMALL,C,FARSTACK would specify that the stack not be included in DGROUP. This capability is already provided in TASM through the language modifiers of the same name. The additional field is provided only for MASM compatibility.

    Two new predefined variables have been added:

      @Startup: Defined by the .STARTUP and STARTUPCODE directives
      @Model: An integer representing the model currently in effect.
          0 = TINY   1 = SMALL    2 = COMPACT    3 = MEDIUM
          4 = LARGE  5 = HUGE
  • New Intel 486 (80486) directives:

    • .486,.486c,.486p (MASM mode only)
    • P486N - Enables assembly of non-protected instructions for the 486 processor.
    • P486 - Enables assembly of protected instructions for the 486 processor.
  • New Intel 486 (80486) instructions:

    BSWAP <32-bit register> - 486 byte swap instruction.
    XADD <r/m>,<reg> - 486 exchange and add instruction.
    CMPXCHG <r/m>,<reg> - 486 compare and exchange instruction.
    INVD - 486 invalidate data cache instruction.
    WBINVD - 486 write back and invalidate data cache inst.
    INVLPG <memptr> - 486 invalidate TLB entry for address inst.
  • New test registers:

    • TR3
    • TR4
    • TR5
  • New error messages:
    • Global type doesn't match symbol type
    • Illegal segment address
    • Module is pass-dependent--compatibility pass was done.
    • Near jump or call to different CS
    • Only one startup sequence allowed
    • Smart code generation must be enabled
    • Text macro expansion exceeds maximum line length
    • USES has no effect without language
  • CODEPTR type:
    CODEPTR returns the default procedure address size depending on the current model (WORD for models with NEAR code; DWORD for models with FAR code). CODEPTR can be used wherever DATAPTR is used. Here is its syntax:
        CODEPTR expression
  • RETCODE instruction:
    The RETCODE instruction is exactly equivalent to RETN or RETF, depending on the specified model. RETCODE syntax follows:
        RETCODE {<expression>}
    RETCODE is available in both MASM and Ideal modes.
  • SMART/NOSMART directives:
    The SMART/NOSMART directives control the generation of optimized object code. These are the areas that the SMART and NOSMART directives apply to:

    1. OR, AND, or XOR of a signed immediate byte
    2. PUSH <constant>
    3. PUSH <large pointer>
      POP <large pointer>
    4. CALL <far address in same segment>
    5. JMP <far address in same segment>
    6. LEA <constant effective address>
    The default condition is SMART enabled. When SMART is enabled, a qualifying FAR jump will be replaced by a NEAR or a SHORT jump. Also, when SMART is enabled, a qualifying FAR call will be replaced by a PUSH CS instruction and a NEAR call.

    When NOSMART is selected, the following code generation changes occur:

    • AND, OR, XOR of an immediate word value are no longer done using the signed-extended immediate byte version of these instructions where possible, but rather the longer immediate word version that MASM uses.
    • PUSH of a constant value on the 8086 processor using the special 10-byte code sequence (which preserves all registers and flags) is not allowed.
    • PUSH and POP of a DWORD memory variable (or PWORD variable on a 386) are not allowed.
    • Far JMPs and CALLs within the same segment are no longer optimized by replacing the FAR JMP or CALL with the NEAR version.
    • LEA instructions that refer to a constant effective address will no longer be converted to the equivalent MOV operations.
    For maximum MASM compatibility, you must select NOSMART and QUIRKS.
  • Overlay object code:
    Turbo Assembler 2.0 supports overlays. Specifying the /o switch on the command line causes overlay- compatible fixups to be generated. When this switch is used, 386 references to USE32 segments should not be made since they won't link properly.
  • Updated QUIRKS mode list:
    The following apply to QUIRKS mode:
    • NEAR or SHORT jumps are generated even if FAR is specified, if source and destination segments are the same.
    • Type checking for some two-argument instructions is disabled, for example, MOV ES,BYTEPTR is allowed.
    • Forces an EQU to an expression with PTR in it to be a text macro.
    • Forces an EQU to an expression with : in it to be a text macro.
    • Forces an EQU to an expression with OFFSET in it to be a text macro.
    • Forces SHL operator to lose track of sign info.
    • Forces numeric equates (= or numeric EQU) to lose complex expression information such as segment, fixup type.
    • Reduces priority of GLOBAL, UNION keywords so that they may be overridden.
    • Causes warning instead of error to be generated if the second argument is missing in a two-argument instruction.
    • Allows REPT without argument to be interpreted as REPT 0.
    • Disables test for extra stuff on line after IF conditional.
    The following apply to QUIRKS with MASM51:
    • @@, @F, and @B are enabled.
    • Trailing language ID after NEAR or FAR in procedure declaration is allowed.
    • All procedure symbols are published globally.
    • :: label definitions are allowed.
  • Command Line Options Added:
    [bytepointer.com edit] Some of these explained above.

    /mv# - Set maximum valid length for symbols
    /m# - Allow # multiple passes to resolve forward references
    /o,/op - Generate overlay object code, Phar Lap-style 32-bit fixups
    /q - Suppress OBJ records not needed for linking
  • Language_modifier Keywords Added:
    [bytepointer.com edit] The following keywords were found to be new in this version by binary analysis, but undocumented in the changelists; they were all language modifiers in addition to the documented WINDOWS keyword.

    • NORMAL (u)
    • ODDNEAR (u) - used in connection with the VROOM overlay manager
    • ODDFAR (u) - used in connection with the VROOM overlay manager
    The description below came from the TASM 4.0 User's Guide:

    Use language_modifier to specify additional prolog and epilog code when you write procedures for Windows, or for the Borland Overlay loader. These options are: NORMAL, WINDOWS, ODDNEAR and ODDFAR. If you don't specify an option, Turbo Assembler assumes the default to be NORMAL.
    The ODDNEAR and ODDFAR language modifiers are used in connection with the VROOM overlay manager. VROOM has'two modes of operation: oddnear and oddfar. You can use the Ila switch option on the Turbo Assembler command line to see the prolog and epilog code that these language modifiers produce.
  • New Warning Class Identifiers:

    • GTP (u) - Global type doesn't match symbol type
    • MCP (u) - MASM compatibility pass
  • Possible Undocumented-Feature Keywords:

    • CALLPROC (u)
Article: Turbo Tools
from Borland
Highlight Conference
February 12, 1990
Turbo Tools from Borland Highlight Conference
Article: Three Turbo-
charged Programming
Tools from Borland
PC Magazine
September 11, 1990
Three Turbo-charged Programming Tools from Borland

TASM 2.0 Manuals
TASM 2.0 Manuals #1 TASM 2.0 Manuals #2

TASM 2.01 © 1988, 1990 Borland International [Command Line]
TASM.EXE105,651 bytes (103k)md5=91048dc8e05e20d5865a6cf70b6ca48cdate=10/29/1990 2:01am(date from install disks)
??version reports: 513

Although the README and UPDATE.DOC had been updated in this version, they were basically "reworked" versions of the corresponding 2.0 documents with no new information. This version was likely a bugfix release with the only visible change to the command line help.

  • Command Line Options Deleted:
    The /ks# option (String space capacity) was removed. This was previously on the same line with the /kh option (Hash table capacity) which now reads "Hash table capacity # symbols".

TASM 2.02 © 1988, 1990 Borland International [Command Line]
TASM.EXE71,283 bytes (70k)md5=da7d0e8a3fb18afd93d5f35b630c04e0date=3/13/1991 3:02am
??version reports: 514

This version had the smallest executable size of any TASM, even 1.0! Because of this, I originally suspected this version to be a fake, but it turns out that the binary was packed with PKLITE V1.12. The DOS unpacker TRON restored the file from 71283 bytes (70k) to 106105 bytes (104k) allowing binary analysis and putting the file size perfectly on par with the sizes of the sibling versions. Unpacked, this version is 416 bytes smaller than version 2.5. It is also interesting to note that the linker (TLINK.EXE) as well as the rest of the executable files (EXE and COM) in the distribution I have were also packed with PKLITE. This is the only version of TASM I've seen that has had an EXE packing applied.

Since version 2.01, there were no documented changes to the product. The README changes consisted of a search and replace of the number 2.01 with 2.02 and Borland's Technical Support zip code changed from 95066 to 95067. Otherwise, all other DOC files, including the UPDATE.DOC were identical.

Binary analysis and testing however showed the presence of new keywords not yet officially documented. Keywords revealed by binary analysis NOT present in any available changelist documentation are denoted by a "(u)". Some descriptions were derived from the TASM 4.0 manual:

  • Beta Feature Instructions?:
    [bytepointer.com edit] Binary analysis showed the presence of the following instructions, which were not officially supported until version 2.5, but will assemble without error in this version:

    • ENTERW (u)
    • ENTERD (u)
    • LEAVEW (u)
    • LEAVED (u)
  • New Segment Alignment Attribute

    • MEMPAGE (u) - Start a segment on the next memory page (4Kb aligned) address.
  • New Segment Access Attributes

    For any segment in protected mode, you can control access so that certain kinds of memory operations are not permitted. (Note that this feature is currently supported only by the Phar Lap linker. You must generate object code compatible with it using the /op switch if you want to be able to use the segment access attribute.) The segment access attribute tells the linker to apply specific access restrictions to a segment. The legal values for this attribute are listed below.

    • EXECONLY (u) - the segment is executable only
    • EXECREAD (u) - the segment is readable and executable
    • READONLY (u) - the segment is readable only
    • READWRITE (u) - the segment is readable and writable
  • New Memory Model

    • TCHUGE (u) - this is the recommended memory model (for use with .MODEL directive) when linking with modules built with the Borland C++ huge memory model; this is the same as the LARGE model, but with different segment register assumptions.
  • New Error Message (u) - "32-bit value truncated to 16 bits"

TASM 2.5 © 1988, 1991 Borland International
TASM.EXE106,521 bytes (104k)md5=00b07efeb49c7163c55234e9bdccedc1date=2/13/1991 2:00am(from Borland C++ 2.0)[Command Line]
TASMX.EXE109,234 bytes (107k)md5=f9f61f370406b0e9bba4b137ceca1129date=2/13/1991 2:00am(from Borland C++ 2.0)[Command Line]
??version reports: 517

A README wasn't available to me for this version, but the changelist and descriptions were was derived from the TASM 4.0 User's Guide. Binary analysis shows very little changes to the executable between version 2.02 (unpacked) and this version as the prior version appeared to have implemented all the features already. These features were probably being beta tested in 2.02.

  • Introduction of TASMX.EXE (DOS Protected Mode Assembler):
    [bytepointer.com edit] This appears to be the first version distributed with TASMX.EXE, designed for assembling 16 and 32-bit binaries. The Borland C++ 2.0 README described TASMX.EXE as follows:

    Two versions of Turbo Assembler have been provided. TASMX.EXE can be run from the Windows DOS prompt, and takes advantage of the DOS Protected Mode Interface (DPMI) that Windows 3.0 provides. This allows the assembler to take advantage of Windows' memory management and to dramatically increase capacity. TASM.EXE uses standard DOS memory, and is provided for operation in environments without DPMI support such as DOS and the non-386 enhanced modes of Windows.
    In order to take advantage of DPMI support feature, you must be running Windows in 386 enhanced mode.
    Enhanced mode is not available when Windows 3.0 is run on processor less than a 386.) Also, DPMILOAD.EXE must be somewhere in your path.
    TASMX is not designed to be a Windows application, so you must enter a Windows 3.0 DOS prompt to use TASMX. Then to use TASMX, just type TASMX wherever you would normally type TASM. All command-line options are the same as the previous version of TASM. When run within the Windows 3.0 DOS prompt, TASMX will be able to use almost all the free memory in the system, if neccessary, for assembling large programs.
    TASM 2.5 will still run without Windows 3.0 DPMI. If DPMI support is not found, you must have TASM.EXE somewhere in your path. Then if you load TASMX, it will run TASM.EXE within the normal 640K DOS environment. Turbo Assembler will not be able to assemble programs larger than normal without DPMI support.
    We encourage you to try TASMX on all your assembler source code, both from the normal DOS prompt and from within a Windows 3.0 DOS prompt. TASMX should be able to handle all programs that work properly with TASM 2.01.

  • New Instructions (available in 2.02, but official in this version):

    • ENTERD
    • LEAVED
    • ENTERW
    • LEAVEW
    Additional 80386 ENTER and LEAVE instructions:
    Use the ENTER and LEAVE instructions for setting up and removing a procedure's frame on the stack. Depending on whether the current code segment is a 32-bit segment or a 16-bit segment, the standard ENTER and LEAVE instructions will modify either the EBP and ESP 32-bit registers, or the BP and SP 16-bit registers. These instructions might be inappropriate if the stack segment is a 32-bit segment and the code segment is a 16-bit segment, or the reverse.

    Turbo Assembler provides four additional instructions that always select a particular stack frame size regardless of the code segment size. The ENTERW and LEAVEW instructions always use BP and SP as the stack frame registers, while the ENTERD and the LEAVED instructions always use EBP and ESP.

TASM 2.51 © 1988, 1991 Borland International [Command Line]
TASM.EXE106,521 bytes (104k)md5=cdc904c8c97f3650ace52db8a185edab
??version reports: 517

Like some of TASM's other minor releases, official information on this version is unknown. Official file date information is also unknown however sibling versions place it in the 1991 releases, matching its reported copyright. Official or not, it was likely a quick-fix release (likely originating as a patch) distributed prior to the supported corresponding fixes in version 3.0. The reported version number did not change.

Binary analysis shows only a total difference of 32 bytes from version 2.5 and the file size remained the same. Besides the reported version on the command line, no other string differences were found.

TASM 3.0 © 1988, 1991 Borland International
TASM.EXE115,471 bytes (113k)md5=9ffe8c8936a5483edf27ccde738d234fdate=11/11/1991 4:00am[Command Line]
TASMX.EXE142,186 bytes (139k)md5=3ae74448b910c1d0a44ff9d67ce4cebfdate=11/11/1991 4:00am[Command Line]
??version reports: 768

Following Microsoft's major MASM 6.0 release, which added 32-bit support for OS/2's flat memory model, Borland responded with this version of TASM about 7 months later. Borland clearly added some important features, such as object-oriented capabilities not supported by MASM, but chose not to add support for MASM's 6.0 syntax. With seemingly exacting precision, Microsoft responded with the release of MASM 6.1 within 1 week of TASM 3.0, further solidifying what would later become known as the standard MASM syntax that remains to this day. In addition to the new flat model support for NT, Microsoft also finally added features to make its own MASM near-100% compatible with the MASM 5.1 syntax. For the first time since its inception, TASM was no longer near-100% MASM compatible and Microsoft was ahead of Borland for the first time EVER, at least in terms of MASM compatibility and operating system support. For those that liked TASM's for its IDEAL mode, TASM was still considered a great, fast and cheaper alternative to MASM.

One of the major additions to version 3.0 was TASM's object-oriented capabilities. MASM never supported any object-oriented features and I think Borland was hoping this would set TASM apart. Although not required, the User's Guide highly recommends using IDEAL mode when using the proprietary and specialized object-oriented syntax. In a section titled "Why use objects in Turbo Assembler?", the User's Guide provides the following explanation:

Most people think of assembly language as a low-level language. Turbo Assembler, however, provides many of the features of a high-level language (such as abstract data types, and easy interfacing to other languages). The addition of object-oriented data structures gives Turbo Assembler the power to create object-oriented programs as easily as high-level languages while retaining the speed and flexibility of assembly language.

Trial and error shows that this was the first version to support the FLAT model, and therefore it can be assumed it was the first version to support assembling 32-bit binaries despite the assembler itself running under DOS. This FLAT model 32-bit support was exclusively for OS/2 as the Windows NT 3.1 operating system debut wouldn't be released for another 2 years (on 7/27/1993). The 32-bit protected-mode assembler (TASM32.EXE) would not be available until version 4.0.

A README wasn't available to me for this version, but the keyword changes were derived from the TASM 4.0 User's Guide and binary analysis. Keywords revealed by binary analysis NOT present in any available changelist documentation are denoted by a "(u)". The keywords that are completely undocumented as to their function, even in future documentation, are listed in the possible undocumented features section at the bottom. Descriptions were also derived from the TASM 4.0 User's Guide.

  • Directives:

    • VERSION:
      The VERSION directive allows you to emulate a specific version of Turbo Assembler or MASM you've written particular modules for. This is helpful for upward and downward compatibility of various versions of TASM and MASM. The VERSION directive also puts you into the operating mode for the specified version. You can specify the VERSION directive as either a command-line switch (/u) or within the source code. Previous versions of Turbo Assembler controlled MASM compatibility with directives such as MASM51, NOMASM51, QUIRKS, SMART, and NOSMART. The VERSION directive supersedes these older directives.

      • M400 - MASM 4.0
      • M500 - MASM 5.0
      • M510 - MASM 5.1
      • M520 - MASM 5.2 (Quick Assembler)
      • T100 - Turbo Assembler 1.0
      • T101 - Turbo Assembler 1.01
      • T200 - Turbo Assembler 2.0
      • T250 - Turbo Assembler 2.5
      • T300 - Turbo Assembler 3.0
    • GOTO:
      Using macro tags and the GOTO directive lets you control the sequence in which lines within the macro body expand. You can place a macro tag at any place within the macro body. The tag occupies an entire line in the macro, with the following syntax:
      When the macro expands, all macro tags are discarded. The GOTO directive tells the assembler to go to a specified point in your code, namely the tag_symbol. GOTO has the following syntax:
          GOTO tag_symbol
      GOTO also terminates any conditional block that contains another GOTO. This lets you place GOTO inside conditional assembly blocks. For example,
          IF foo
             GOTO tag1
             DISPLAY "foo was false!"
                    ;resume macro here...
                    ;works the same whether foo was false or true
      NOTE: Be careful not to create infinite macro loops when you use the GOTO directive. Infinite loops can cause Turbo Assembler to run out of memory, or even appear to stop functioning.
    • TYPEDEF:
      Named types represent simple or complex types. You can use the TYPEDEF directive to define named types. Here's the Ideal mode syntax:
         TYPEDEF type_name complex_type
      The MASM mode syntax is:
         type_name TYPEDEF complex_type
      complex_type describes any type or multiple levels of pointer indirection. type_name is the name of the specified type. When you use a named type in an expression, it functions as if it were a simple type of the appropriate size. For example,
             MOV ax,word ptr [bx]    ;Simple statement;
          foo TYPEDEF near ptr byte     ;FOO is basically a word
             MOV ax,foo ptr [bx]     ;so this works too
    • ENUM:
      An enumerated data type represents a collection of values that can be stored in a certain number of bits. The maximum value stored determines the actual number of bits required. Here is the Ideal mode syntax for declaring an enumerated data type:
          ENUM name [enum_var [,enum_var...]]
      You can use the following syntax in MASM mode:
          name ENUM [enum_var [,enum_var...]]
      The syntax of each enum_var is:
          var_name [=value]
      Turbo Assembler will assign a value equal to that of the last variable in the list plus one if value isn't present when you assign the specified value to the variable var_name. Values can't be relative or forward referenced. Variables that ENUM created are redefinable numeric variables of global scope. name is the name of the ENUM data type. You can use it later in the module to obtain a variety of information about the values assigned to the variables detailed. You can also use enumerated data type names to create variables and allocate memory.

      Enumerated data types are redefinable. You can define the same name as an enumerated data type more than once in a module. Turbo Assembler provides a multiline syntax for enumerated data type definitions requiring a large number of variables. The symbol { starts the multiline definition, and the symbol } stops it. The Ideal mode syntax follows:
          ENUM name [enum_var [,enum_var...]] {
          [enum_var [,enum_var]...]
          [enum_var [,enum_var]...] }
      You can use the following syntax in MASM mode:
          name ENUM [enum_var [,enum_var...]] {
          [enum_var [,enum_var]...]
          [enum_var [,enum_var]...] }
      For example, all of the following enumerated data type definitions are equivalent:
          foo ENUM  fl,f2,f3,f4       ;Original version
          foo ENUM {                  ;Multiline version
         foo ENUM fl,f2,{             ;More compact multiline version
      Beware: If you use the same variable name in two enumerated data types, the first value of the variable will be lost and errors could result.

      NOTE: Turbo Assembler doesn't recognize any pseudo ops inside the multiline enumerated data type definition.

      You can create an instance of an enumerated data type by using the name of the enumerated data type as a data allocation directive. For example, assume you have defined the following:
      Then the statement
         ETEST ETYPE ?
      would create an instance of the enumerated data type etype (defining the variable etest). In this example, no initial data is emitted to the current segment because the ? uninitialized data value is specified. Enumerated data type instances are always either a byte, a word, or a doubleword, depending on the maximum value present in the enumerated data type definition.

      You can use any expression that evaluates to a number that will fit within the enumerated data type instance; for example,
          ETYPE ?     ;uninitialized instance
          ETYPE FOO   ;initialized instance, value FOO
          ETYPE 255   ;a number outside the ENUM that also fits
    • SMALLSTACK and LARGESTACK directives:
      A procedure's prolog and epilog code manipulates registers that point into the stack. On the 80386 or 80486 processor, the stack segment can be either 16 bits or 32 bits. Turbo Assembler therefore must know the correct size of the stack before it can generate correct prolog and epilog code for a procedure. The stack size is automatically selected if you selected a standard model using the MODEL statement. Turbo Assembler provides directives that can set or override the default stack size for procedure prolog and epilog generation. The following table lists these directives.

      SMALLSTACK - Indicates that the stack is 16 bit
      LARGESTACK - Indicates that the stack is 32 bit

    • TBLINST:
      The virtual method table (VMT) is a table of addresses of the procedures that perform virtual methods. Usually this table is placed in the program's data segment. Any object having virtual methods requires an instance of the VMT somewhere in the program. A number of factors determine the proper placement of this table, including what program model you're using, whether you want near or far tables, and so forth. Use the TBLINST directive to create the instance of the VMT for an object. Since this directive creates a table for the most recently declared object, you should place this directive immediately after the object declaration, as in the following:
          INCLUDE list.aso
      TBLINST defines @TableAddr_<object_name> as the address of the virtual table for the object. It is equivalent to
          @TableAddr_<object_name> @Table_<object_name> {}
    • TBLINIT:
      Simply creating the instance of the VMT is not enough to let you make calls to virtual methods. Every object with virtual methods includes a pointer to the VMT in its data structure. You must initialize this pointer whenever you create an instance of an object, and can use TBLINIT to do so. The syntax of the TBLINIT instruction is
         TBLINIT object_instance_pointer
      The object_instance_pointer field is the address of the object whose virtual table pointer is to be initialized. The TBLINIT instruction assumes that the object instance should be of the current object type (in other words, the immediately preceding object definition determines the object type that TBLINIT initializes). For example,
          TBLINIT DS:SI
      would initialize the virtual table pointer of the object at DS:SI, if it has one.

      The following example initializes the VMT pointer in an object's init method:
          ;Initialize a Linked List object.
          ;This is the method "init".
          ;This must be a static method!
          list_init PROC PASCAL FAR
          ARG @@list:dword
          USES ds,bx
               lds bx,@@list
               ;-- Initialize any virtual method table for the object at ds:bx
               TBLINIT ds:bx
               ;-- Initialize the object's data --
               ;;<<initialize any data for the object here...>>
      Notice that the init method must be static because you can't call a virtual method for an object instance until after you initialize the virtual table pointer.

      Note that you can use the TBLINST and TBLINIT directives even when there are currently no virtual methods in the object; in that case, no action is taken. It is therefore recommended to using the TBLINST and TBLINIT directives regardless of whether virtual methods are currently present in an object: Place the TBLINST directive in an appropriate data segment and the TBLINIT directive in the object's initialization method (which must be a static method). You must call this method before using any other methods for the object.
    • TBLPTR:
      Inherent in the idea of objects is the concept of the virtual method table. An instance of this table exists once for any object having virtual methods. The data structure for any object having virtual methods also must contain a pointer to the virtual method table for that object. Turbo Assembler automatically provides a virtual method table pointer in an object's data structure (if required) and if you don't specify it explicitly using the TBLPTR directive. You should use the TBLPTR directive within an object data structure definition. TBLPTR lets you explicitly locate the virtual table pointer wherever you want. Here's its syntax:
      The size of the pointer that TBLPTR reserves is determined by whether the current model is USE16 or USE32, and what modifiers you used in the object definition.
    • TABLE:
      A table data type represents a collection of table members. Each member has a specific size (in bytes) and an initial value. A table member can be either virtual or static. A virtual member of a table is assigned an offset within the table data type; space is reserved for it in any instance of the table. A static member does not have an offset; space isn't reserved for it in an instance of the table. The size of the table data type as a whole is the sum of the sizes of all of the virtual members. Table data types represent method tables, used in object-oriented programming. An object usually has a number of methods associated with it, which are pointers to procedures that manipulate instances of the object. Method procedures can either be called directly (static methods) or indirectly, using a table of method procedure pointers (virtual methods). You can use the following Ideal mode syntax for declaring a table data type:
          TABLE name [table_member [,table_member...]]
      The following syntax works only in MASM mode:
          name TABLE [table_member [,table_member...]]
      Here's the syntax of each table_member field:
          [VIRTUAL] member_name [[count1_expression]]
              [: complex_type [:count2_expression]] [= expression ]
      table_name is the name of an existing table data type whose members are incorporated entirely in the table you define. Use this syntax wherever you want inheritance to occur. member_name is the name of the table member. The optional VIRTUAL keyword indicates that the member is virtual and should be assigned to a table offset. complex_type can be any legal complex type expression. If you don't specify a complex_type field, Turbo Assembler assumes it to be WORD (DWORD is assumed if the currently selected model is a 32-bit model). count2_expression specifies how many items of this type the table member defines. A table member definition of
          foo TABLE VIRTUAL tmp:DWORD:4
      defines a table member called tmp, consisting of four doublewords. The default value for count2_expression is 1 if you don't specify it. count1_expression is an array element size multiplier. The total space reserved for the member is count2_expression times the length specified by the memtype field, times count1_expression. The default value for count1_expression is also 1 if you don't specify one. count1_expression multiplied by count2_expression specifies the total count of the table member. Table member names are local to a table in Ideal mode, but are global in scope in MASM mode. name is the name of the table data type. You can use it later in the module to get a variety of information about the table data type. You can also use the names of individual table members to obtain information. Table data types are redefinable. You can define the same name as a table data type more than once in a module. You can also use table data type names to create variables and allocate memory. Alternatively, Turbo Assembler provides a multiline syntax for table data type definitions requiring a large number of members. This syntax is similar to that of enumerated data type definitions. Here's an example:
          foo TABLE t1:WORD,t2:WORD,t3:WORD,t4:WORD ;Original version
          foo TABLE {       ;Multiline version
          foo TABLE tl:WORD,t2:WORD,{      ;More compact multiline version
      If you declare two or more members of the same name as part of the same table data type, Turbo Assembler will check to be sure that their types and sizes agree. If they don't, it will generate an error. Turbo Assembler will use the last initial value occurring in the table definition for the member. In this way, you can override the initial value of a table after it is incorporated into another. For example,
          FOO2 TABLE FOO, VIRTUAL MEM1:WORD=MEM3PROC ;Overrides inherited
      To create an instance of a table data type, use the table name as a data allocation directive. For example, assume you have defined the following table:
          TTYPE TABLE  VIRTUAL MoveProc:WORD=MoveRtn,     \
               VIRTUAL MsgProc:DWORD=MsgRtn,              \
               VIRTUAL DoneProc:WORD=DoneRtn
      Then, the statement
          TTEST TTYPE ?
      would create an instance of the table ttype (defining the variable ttest). No initial data will be emitted to the current segment in this example because the ? uninitialized data value was specified.

      When you define a table, you must specify an initial value for all table members. The simplest initialized instance of a table contains just the initial data specified in the definition. For example,
          TTYPE {}
      is equivalent to
          DW MoveRtn
          DD MsgRtn
          DW DoneRtn
      The braces ({ }) represent a null initializer' value for the structure. The initializer value determines what members (if any) have initial values that should be overridden, and by what new values, as you allocate data for the table instance. Here's the syntax of the brace initializer:
          { [member_name = value [,member_name = value...]] }
      member_name is the name of a member of the table. value is the value that you want the member to have in this instance. A blank value indicates that you'll use the initial value of the member from the table definition. A ? value indicates that the member should be uninitialized. Turbo Assembler sets any member that doesn't appear in the initializer to the initial value of the member from the table definition. For example,
          TTYPE {MoveProc=MoveRtn2,DoneProc=?}
      is equivalent to
          DW MoveRtn2
          DD MsgRtn
          DW ?
      When you declare an object, Turbo Assembler creates a STRUC that declares the data for the object, and a TABLE that declares the methods for the object. The object's data declaration is a structure with the same name as the object. The object's method declarations are stored in a TABLE data type, named @Table_<objectnarne>. For example, for the list object, two data types are declared:
      list           A STRUC declaring the following members:
                     list_head    dword pointer to head of list
                     list_tail    dword pointer to tail of list
      @Table_list    A TABLE declaring the following methods:
                     construct    dword pointer to the procedure list_construct
                     destroy      dword pointer to the procedure list_destroy
                     and so on ...
      STRUC declares the data for the object that is created whenever you create an instance of the object. TABLE declares the table of default method procedures for the declaration. Turbo Assembler maintains this data type; it does not create an instance of the table anywhere in your program memory. However, you'll see later that you must include an instance of the table for any object that uses virtual methods.
    • Object-Oriented Symbols/Types:
      The extended STRUC directive defines or uses several symbols, which reflect the object being defined. The following table shows these symbols:

      @Object   A text macro containing the name of the current object (the object last declared).
      <objectname> A STRUC data type that describes the object's data structure.
      @Table_<objectname> A TABLE data type containing the object's method table, which is not the same as an instance of the virtual method table.
      @TableAddr_<objectname> A label describing the address of the instance of the object's virtual method table, if there is one.
      @Mptr_<objectname> this is an object member that points to a table of virtual method pointers; present in objects with virtual methods.

    • WHILE:
      You can use the WHILE macro directive to repeat a macro body until a certain expression evaluates to 0 (false). WHILE has the following syntax:
          WHILE while_expression
      Turbo Assembler evaluates while_expression before each iteration of the macro body. Be careful to avoid infinite loops, which can cause Turbo Assembler to run out of memory or appear to stop functioning. Here's an example using WHILE:
          WHILE 1
              ;; Do nothing
              ; We never make it this far
      You can use the EXITCODE directive to produce termination code appropriate for the current operating system. You can use it more than once in a module, for each desired exit point. Here's its syntax:
          EXITCODE [return_value_expr]
      You can use the following syntax only in MASM mode:
          .EXIT [return_value_expr]
      The optional return_value_expr describes the number to be returned to the operating system. If you don't specify a return value, Turbo Assembler assumes the value in the AX register.
    • .EXIT (u):
      (see description in EXITCODE above)
    • EXIT (u):
      [bytepointer.com edit] Undocumented but likely a synonym for .EXIT
  • Instructions:

    • FASTIMUL (Fast Immediate Multiply Instruction):
      Turbo Assembler provides a special immediate multiply operation for efficient array indexing. FASTIMUL addresses a typical problem that occurs when you create an array of structures. There is no immediate multiply operation available for the 8086 processor. Even for the more advanced processors, multiplication using shifts and adds is significantly faster in some circumstances than using the standard immediate IMUL instruction. Based on the currently specified processor, Turbo Assembler's FASTIMUL instruction chooses between the most efficient sequence of shifts and adds available, and the current processor's immediate IMUL operation (if any). FASTIMUL has the following syntax:
          FASTIMUL dest_reg, source_r/m, value
      This instruction is much like the trinary IMUL operation available on the 80186, 80286, and 80386 processors. The dest_reg destination register is a WORD register (or it can be DWORD on the 80386). source_r/m is a register or memory address that must match the size of the destination. value is a fixed, signed constant multiplicand. FASTIMUL uses a combination of IMUL, MOV, NEG, SHL, ADD, and SUB instructions to perform its function. This function destroys the source register or memory address, and leaves the processor flags in an indeterminate state.
    • SETFLAG - a "smart-flag" instruction implementing OR
    • TESTFLAG - a "smart-flag" instruction implementing TEST
    • FLIPFLAG - a "smart-flag" instruction implementing XOR
    • CLRFLAG - [bytepointer.com edit] I think this is a doc bug where the writers meant to specify MASKFLAG as CLRFLAG does not exist and likely never existed; there is no CLRFLAG identifier embedded within this version or any version of TASM; CLRFLAG is also not documented anywhere else but the one place it was ever mentioned: the keywords table for version 3.0.
    • MASKFLAG (u) - a "smart-flag" instruction implementing AND; accidentally documented in the new keywords for version 3.0 table as CLRFLAG
      SETFIELD generates code that sets a value in a record field. Its syntax follows:
          SETFIELD field_name destination_r/m, source_reg
      field_name is the name of a record member field. destination_r/m for SETFIELD is a register or memory address of type BYTE or WORD (or DWORD for the 80386). source_reg must be a register of the same size or smaller. If the source is smaller than the destination, the source register must be the least significant part of another register that is the same size as the destination. This full-size register is called the operating register. Use this register to shift the value in the source register so that it's aligned with the destination. For example,
          FOO    RECORD R0:1,R1:4,R2:3,R3:1
             SETFIELD R1 AX,BL                ;operating register is BX
             SETFIELD R1 AX,BH                ;illegal!
      SETFIELD shifts the source register efficiently to align it with the field in the destination, and ORs the result into the destination register. Otherwise, SETFIELD modifies only the operating register and the processor flags. To perform its function, SETFIELD generates an efficient but extended series of the following instructions: XOR, XCHG, ROL, ROR, OR, and MOVZX. The entire contents of the operating register are destroyed by the SETFIELD operation.

      If you're using SETFIELD when your source and target registers are the same, the instruction does not OR the source value to itself. Instead, SETFIELD ensures that the fields of the target register not being set will be zero. SETFIELD does not attempt to clear the target field before ORing the new value. If this is necessary, you must explicitly clear the field using the MASKFLAG instruction.
      GETFIELD retrieves data from a record field. It functions as the logical reverse of the SETFIELD instruction. Its syntax follows:
          GETFIELD field_name destination_reg, source_r/m
      field_name and destination_reg function as they do for SETFIELD. You can use source_r/m as you would for source_reg (for SETFIELD). For example,
          FOO    RECORD R0:1,R1:4,R2:3,R3:1
             GETFIELD R1 BL,AX                 ;operating register is BX
             GETFIELD R1 BH,AX                 ;illegal!
      Note that GETFIELD destroys the entire contents of the operating register. GETFIELD retrieves the value of a field found in the source register or memory address, and sets the pertinent portion of the destination register to that value. This instruction affects no other registers than the operating register and the processor flags. To accomplish its function, GETFIELD generates an efficient but extended series of the following instructions: MOV, XCHG, ROL, and ROR. If you're using the GETFIELD instruction when your source and target registers are the same, the instruction will not generate the nonfunctional MOV target, source instruction.
  • Symbols:

    • @32Bit (u):
      The @32Bit symbol contains an indication of whether segments in the currently specified model are declared as 16 bit or 32 bit. The symbol has a value of 0 if you specified 16-bit segments in the, MODEL directive, or 1 if you indicated 32-bit segments.
    • @Interface (u):
      The @Interface symbol provides information about the language and operating system selected by the MODEL statement. This text macro contains a number whose bits represent the following values:

      Value in bits 0-6  Meaning

      Bit 7 can have a value of 0 for DOS/Windows, or 1 for Windows NT. For example, the value 81h for @Interface shows that you selected the Windows NT operating system and the C language.
    • @stack (u):
      a "simplified segment directives" symbol containing the segment or group that SS is assumed to be.
  • Keywords:

    • METHOD (u):
      Consider the following example declaration:
          list STRUC GLOBAL METHOD {
            construct:dword = list_construct   ;list constructor procedure
            destroy:dword = list_destroy       ;list destructor procedure
            init:dword = list_init             ;list initializer procedure
            deinit:dword = list_deinit         ;list deinitializer procedure
            virtual insert:word = list_insert  ;list node insert procedure
            virtual append:word = list_append  ;list node append procedure
            virtual remove:word = list_delete   ;list node remove procedure
            virtual first:word = list_first    ;list first node procedure
            virtual last:word = list_last      ;list last node procedure
            list_head   dd ?                   ;list head pointer
            list_tail   dd ?                   ;list tail pointer
      Let's look at this example to see what's happening.

      The METHOD keyword shows that you're using an extended form of STRUC, and are defining an object called list. Each entry consists of a method name, a colon, and the size of a pointer to the method procedure (WORD for near procedures, DWORD for far procedures). This is followed by an equal sign, and the name of the procedure to call for that method.

      METHOD indicates an object method call and is followed by a list of the method procedure declarations for the object. These declarations are 'enclosed in braces ({ }) because the list of methods requires more than one line. Each method declaration tells Turbo Assembler which procedure it should use to manipulate the object when invoking that method name. For example, the first method procedure declaration
          construct:dword = list_construct
      declares a method named construct that is a far procedure (because a DWORD stores the pointer to it). The actual procedure name of the method is list_construct, which should be defined elsewhere in the source code. Turbo Assembler considers a method to be virtual if it's preceded by the keyword VIRTUAL. When you call such a method, Turbo Assembler will locate the method's procedure address by looking it up from a table present in memory at run time. Otherwise, the method is a static method, meaning that Turbo Assembler can determine its address at compile time. For example, the method construct is a static method, while the method insert is declared as a virtual method. The data structure for the method immediately follows the method procedure declaration section. This definition uses the syntax for the standard STRUC directive. This example contains declarations for the linked list's head and tail pointers. The method declaration portion of the object declaration doesn't place any data in the object's data structure unless you've used virtual methods. Instead, these declarations cause Turbo Assembler to build a separate table data structure that contains the specified method procedure addresses as default values. You should have an instance of this table for every object, and you must explicitly place the table.
  • Memory Models:

    • FLAT (u) - This is the same as the SMALL model, but tailored for use under OS/2.
  • Model Modifiers:

    • OS_DOS (u) and DOS (u) - Both keywords specify that DOS is the platform for the application.
    • OS_OS2 (u) and OS2 (u) - Both keywords specify that OS/2 is the platform for the application.
  • Dummy Argument Types:

    Each dummy argument has the following syntax:
    dummy_name is a symbolic name used as a place holder for the actual argument passed to the macro when it's invoked. The optional dummy_type specifies something about the form the actual argument must take when you invoke the macro. The following types are supported:

    • REQ (u) - Argument cannot be null or spaces.
    • =<text_string> - Bracketed text string is the default value for the dummy argument when the actual argument is null or contains spaces.
    • REST (u) - Actual argument consists of the rest of the macro invocation, interpreted as raw text.
    • VARARG (u) - Actual argument consists of the rest of the macro invocation, interpreted as a list of arguments. Commas and angle brackets are added to ensure this interpretation.
  • Calling Conventions:

    • CPP (u) - specifies the C/C++ calling convention; name must start with _. The rest of name should be in lowercase characters (_name).
      [bytepointer.com edit] Besides the use of CPP returning a different bit pattern in @Interface, the manual essentially describes this as a synonym for C and PROLOG conventions.
    • SYSCALL (u) - specifies C calling conventions, but without prepending underscores to symbol names (like Pascal naming conventions).
  • Command Line Options added:
    /uxxxx - Set version emulation, version xxxx
    /zi,/zd,/zn - Debug info: zi=full, zd=line numbers only, zn=none

    [bytepointer.com edit] In the "Debug info" line above, only the /zn option was new with this version.

  • @Model Symbol:
    [bytepointer.com edit] Although undocumented as to the exact version between 2.0 and 3.0, by version 3.0, the @Model codes (as listed in the 3.0 User's Guide) had been changed to:
        1 = tiny model is in effect
        2 = small or flat
        3 = compact
        4 = medium
        5 = large
        6 = huge
        7 = tchuge
        0 = tpascal
  • Possible Undocumented-Feature Keywords:

    • CALLMETHOD (u)
    • JMPMETHOD (u)
    • OBJDEF (u)
    • OBJEND (u)
    • PROCBEG (u)
    • PROCEND (u)
TASM 3.0 User's Guide
TASM 3.0 User's Guide

TASM 3.1 © 1988, 1992 Borland International
TASM.EXE129,266 bytes (126k)md5=1386aec2a615e65f3aaffdccf0b66f64date=6/10/1992 3:10am(from Borland C++ 3.1)[Command Line]
TASMX.EXE142,990 bytes (140k)md5=3231b935a5b75c42dfdac60b5d40f895date=6/10/1992 3:10am(from Borland C++ 3.1)[Command Line]
??version reports: 778

This version introduced support for Intel's i487SX (80487) coprocessor, used by the i486SX processor (it was a full-blown i486DX processor internally, but modified slightly for marketing purposes). The TASM 4 and 5 User's Guides incorrectly list the .487 and P487 directives as being present in TASM 1.0. Binary analysis confirms these directives were not present until this version of TASM.

A README wasn't available to me for this version, but the keyword changes were derived from the TASM 4.0 User's Guide and binary analysis. Keywords revealed by binary analysis NOT present in any available changelist documentation are denoted by a "(u)". Descriptions were also derived from the TASM 4.0 User's Guide.

  • New Keywords Introduced:

      The PUSHSTATE directive saves the current operating state on an internal stack that is 16 levels deep. PUSHSTATE is particularly useful if you have code inside a macro that functions independently of the current operating state, but does not affect the current operating mode. Note that you can use PUSHSTATE outside of macros. This can be useful for include files. The state information that Turbo Assembler saves consists of:

      • current emulation version (for example, T310)
      • mode selection (for example, IDEAL, MASM, QUIRKS, MASM51)
      • EMUL or NOEMUL switches
      • current processor or coprocessor selection
      • MULTERRS or NOMULTERRS switches
      • SMART or NOSMART switches
      • the current radix
      • JUMPS or NOJUMPS switches
      • LOCALS or NOLOCALS switches
      • the current local symbol prefix
      Use the POPSTATE directive to return to the last saved state (from PUSHSTATE) from the stack.
    • P487 (u):
      Enables assembly of 487 numeric processor instructions. This instruction works in both MASM and Ideal modes.
    • .487 (u):
      Enables assembly of 487 numeric processor instructions. This instruction works only in MASM mode.
    • UNINIT (u):
      This segment combination attribute produces a warning message to let you know that you have inadvertently written initialized data to uninitialized data segments. For example, you can specify the following to produce a warning message: BSS SEGMENT PUBLIC WORD UNINIT 'BSS'. To disable this warning message, use the NOWARN UNI directive. You can reenable the message by using the WARN UNI directive.
    • T310 (u):
      VERSION directive identifier for [the current] Turbo Assembler 3.1
  • New Warning Class Identifiers:

    • INT (u) - INT 3 generation
    • UNI (u) - For turning off uninitialized segment warning
  • Command Line Options Changed:

    Standard and IBM overlay options added. The overlay command line options were previously listed as:
    /o,/op            Generate overlay object code, Phar Lap-style 32-bit fixups
    With the addition of /os (standard) and /oi (IBM), the options now read as follows:
    /os,/o,/op,/oi    Object code: standard, standard w/overlays, Phar Lap, or IBM

TASM 3.2i © 1988, 1992 Borland International
TASM.EXE133,698 bytes (131k)md5=186d73c0c0b85a91cef1ab4684e47fc1date=10/1/1992 7:00am(from Borland Pascal 7.0)[Command Line]
TASMX.EXE147,064 bytes (144k)md5=a6fefafe494ee7cfd34f32824d8ca9c9date=10/1/1992 7:00am(from Borland Pascal 7.0)[Command Line]
??version reports: 788

This version was found in an earlier release of Borland Pascal 7.0, whereas version 3.2 (without the "i") was seen in a later release of the same product indicating this "i" version was an "internal" or pre-release version. The distribution included manual reference and correction information in the HELPME!.TSM file.

One visible difference of this version of TASM is that the command line displays the following on the second line:
Serial No:   Tester:
We see this Serial/Tester line again in an official Borland release to the public in patched version 5.0r.

The changelist information below was derived from HELPME!.TSM and binary analysis. Keywords revealed by binary analysis NOT present in any available changelist documentation are denoted by a "(u)". Descriptions for the undocumented changes were derived from the TASM 4.0 User's Guide. With the exception of the STDCALL keyword which was an undocumented change for 3.2i and 3.2, all of the keywords listed below were officially documented as new keywords for version 3.2 (the next version), another indicator the changes here were "beta".

  • Greater MASM Compatibility for text equate substitutions:
    Whenever a line requires the expansion of a text macro, use the % operator at the beginning of the line to specifically indicate that the text macros should be expanded before the line is parsed. In previous versions of Turbo Assembler, some instances of text macros (particularly where text macros had the same names as assembly language keywords) would not be expanded. For example, this situation could occur when you define a model on the command line. You could assemble
        .MODEL M
    with the following command line:
         TASM /dM=SMALL A.ASM
    Since Turbo Assembler now requires you to place the % operator at the beginning of the line containing the text equate substitution, this program would change to:
        %  .MODEL M
    If you omit the %, you might receive an "Invalid Model Type" error.
  • New Keywords Introduced:

    • PROCTYPE (u):
      This directive allows you to use user-defined data types (called a procedure type) to describe the arguments and calling conventions of a procedure. Turbo Assembler treats procedure types like any other types; you can use it wherever types are allowed. Note that since procedure types don't allocate data, you can't create an instance of a procedure type. The Ideal mode syntax is:
          PROCTYPE name [procedure_description]
      The MASM mode syntax is:
          name PROCTYPE [procedure_description]
      procedure_description is similar to the language and argument specification for the PROC directive. You can use a procedure type (defined with PROCTYPE) as a template for the procedure declaration itself. For example,
          footype PROCTYPE pascal near :word, :dword,:word
          foo PROC footype                    ;pascal near procedure
          arg a1:word,a2:dword,a3:word        ;an error would occur if
                                              ;arguments did not match
                                              ;those of footype
      When you declare a procedure using a named procedure description, the number and types of the arguments declared for PROC are checked against those declared by PROCTYPE. The procedure description supplies the language and distance of the procedure declaration.
    • PROCDESC (u):
      This directive allows you to declare procedure prototypes much like procedure prototypes in C. Turbo Assembler treats the procedure name as if it were a GLOBAL symbol. If you've defined the procedure within the module, it is treated as PUBLIC. Otherwise, Turbo Assembler assumes it to be EXTRN. You can place PROCDESC directives in an include file. The Ideal mode syntax of PROCDESC is:
          PROCDESC name [procedure_description]
      Use the following syntax in MASM mode:
          name PROCDESC [procedure_description]
      procedure_description is similar to the language and argument specification used in the PROC directive.
    • PUSHAW (u) - forces a WORD-style PUSHA instruction
    • POPAW (u) - forces a WORD-style POPA instruction
    • PUSHFW (u) - forces a WORD-style PUSHF instruction
    • POPFW (u) - forces a WORD-style POPF instruction
    • IRETW (u) - forces a WORD-style flags POP for the IRET instruction
    • T320 (u) - VERSION directive identifier for [the current] Turbo Assembler 3.2
    • STDCALL (u) - uses C calling conventions for procedures with variable arguments, and Pascal calling conventions for procedures with fixed arguments. It always uses the C naming convention.
      [bytepointer.com edit] STDCALL is missing from the official version 3.2 New Keywords list in the User's Guides

TASM 3.2 © 1988, 1992 Borland International
TASM.EXE133,580 bytes (130k)md5=91058c9cfc37d89bb283930ca4a33c13date=3/9/1993 7:01am(from Borland Pascal 7.01)[Command Line]
TASMX.EXE146,988 bytes (144k)md5=f8e7693eb66715005d5a5c57b69b2bbedate=3/9/1993 7:01am(from Borland Pascal 7.01)[Command Line]
??version reports: 788

This version was seen in an later release of Borland Pascal 7.0, whereas version 3.2i was seen in an earlier release of the same product; this seems to indicate this was the "finalized" 3.2 version. ??Version reports the same number as in version 3.2i.

The changelist below was derived from a diff of the earlier HELPME!.TSM and the later HELPME!.TSM files from the two Borland Pascal 7.0 releases along with portions derived and paraphrased from the TASM 4.0 User's Guide. Most of the features that were added in 3.2i (assumed to be "beta"), were announced officially in this version.

  • Variable Argument Lists:
    Syntax for defining arguments passed to a procedure:
        ARG argument [,argument] ... [=symbol]
          [RETURNS argument [,argument]]
    An individual argument has the following syntax:
        argname [[ countl_expression]] [: complex_type [: count2_expression]]
    You can specify count2_expression using the ? keyword to indicate that a variable number of arguments are passed to the procedure. For example, an argument definition of
        ARG tmp:WORD:?
    defines an argument called tmp, consisting of a variable number of words.
  • Segment Overrides:
    Turbo Assembler 3.2 now handles segment overrides in a more consistent manner. All segment overrides in MASM mode programs must occur outside the [] of a memory expression. For example, this line that previous versions of TASM would accept,
        MOV AX,[ES:BX]
    will now generate a warning:
        *Warning* segment.ASM(3) ":" operator ignored
    Also, the segment override will not be generated.

    To fix this warning, and to cause the expected segment override, it is important to move the ES: outside of the memory [], like this:
        MOV AX,ES:[BX]
  • New Keywords present in 3.2i, now official in this version:

    • PUSHAW
    • POPAW
    • PUSHFW
    • POPFW
    • IRETW

TASM 4.0 © 1988, 1993 Borland International
TASM.EXE134,884 bytes (132k)md5=e0b20a28c3a3a5bcce9c2340ec0a4e19date=12/1/1993 4:00am(from Borland C++ 4.0 Upgrade)[Command Line]
TASMX.EXE148,378 bytes (145k)md5=7f66ab8c0e71d0944125267a4686df44date=12/1/1993 4:00am(from Borland C++ 4.0 Upgrade)[Command Line]
TASM32.EXE163,840 bytes (160k)md5=ff6ad95e9f2dfb9396e81ce8e757df2ddate=12/1/1993 4:00am(from Borland C++ 4.0 Upgrade)[Command Line]
??version reports: 1024

This version of TASM introduced support for the Pentium (i586) processor released by Intel on 3/22/1993.

Intel Pentium i586 Processor

Although you could previously build 32-bit binaries for OS/2, this was the first version of TASM to support building 32-bit binaries for Windows NT 3.1, released 7/27/1993 (about 3 months prior to the release of this version). Also included was TASM's first ever 32-bit protected mode assembler (TASM32.EXE). TASM was somewhat more on track with Microsoft's MASM due to the release of the protected mode assembler and NT support, but still offered no support for MASM's 6.x syntax.

This version of TASM was bundled with the Borland C++ 4.0 Upgrade, as noted in the TSM_INST.TXT. The TSM_RDME.TXT (README), unfortunately doesn't contain much information on the changes.

TASM32.EXE for versions 4.0 and 4.1 could not handle quoted filenames on the command line, although this was fixed by version 5.0. Passing a quoted filename resulted in the following error:
**Fatal** Command line: Can't locate file
Another bug present in TASM32.EXE since its inception (4.0 in 1993) to the present (as of TASM 5.4 from 12/7/2013) is that full debugging information (/zi) cannot be specified on the command line with any listing file options (/l or /la). With this combination, TASM32.EXE crashes with an Access Violation; that is when assembling a 32-bit FLAT model module. Passing the same options when either using the SMALL model, or the DOS assembler TASM.EXE, the crash does not occur. This bug is so easy to reproduce, it was most likely known to Borland, but for whatever reason, they never fixed it. The following is the simplest Win32 application that can be used to reproduce the bug, just make sure you pass the /zi and /l options on the command-line:
    call ExitProcess,0
END start
The changelist information was derived from binary analysis, README information (above), and the TASM 4.0 and 5.0 User's Guides (the 4.0 guide was missing most of the keywords). Keywords revealed by binary analysis NOT present in any available changelist documentation are denoted by a "(u)". The keywords that are completely undocumented as to their function, even in future documentation, are listed in the possible undocumented features section at the bottom. However the TASM 5.0 User's Guide incorrectly lists this version as supporting the Pentium's RDTSC and RSM instructions. The RDTSC instruction is not supported until version 5.2b and the RSM instruction has never been supported with any known version of TASM. The TASM 4 User's Guide also incorrectly lists the ALIAS directive and the two Pentium directives .587 and P587 as being present in TASM 1.0. These were corrected in the TASM 5 User's Guide. Binary analysis confirms support for these directives were not present until this version of TASM.

  • 4 MB Extended Memory
  • 80386 processor or higher
  • DOS 4.01 or later
  • Windows 3.1 or later
  • Approximately 2 MB hard disk space
  • Introduction of TASM32 (32-bit Protected Mode Assembler):
    [bytepointer.com edit] This was the first version distributed with TASM32.EXE, designed for running in a 32-bit operating system (as well as building 32-bit Windows binaries). The printed 4.0 manual describes TASM32.EXE as follows:

    Protected-mode assembler. Assembles 16-and 32-bit applications using memory above 640K. Produces only 32-bit debug information.
  • Pentium Directives:

    • P586 - Enables assembly of all Pentium instructions.
    • P586N - Enables assembly of nonprivileged Pentium instructions.
    • .586 (u) - Enables assembly of the additional instructions supported by the Pentium processor in nonprivileged mode.
    • .586C (u) - Enables assembly of all Pentium instructions.
    • .586P (u) - Enables assembly of all the additional instructions supported by the Pentium processor, including the privileged mode instructions.
    • .587 (u) - Enables assembly of Pentium numeric processor instructions. This instruction works only in MASM mode.
    • P587 - Enables assembly of Pentium numeric processor instructions. This instruction works in both MASM and Ideal modes.
  • Pentium Instructions:

    • CPUID
    • RDMSR
    • WRMSR
  • Model Modifiers:

    • OS_NT (u) and NT (u) - Both keywords specify that Windows NT is the platform for the application.
  • Other Keywords Introduced:

    • ALIAS:
      This directive allows the association of an alias name with a substitute name. When the linker encounters an alias name, it resolves the alias by referring to the substitute name.
      [bytepointer.com edit] The README.TXT supplied with the ALIASWIN example contains more information on aliasing. Although I pulled this example from the TASM 5.0 distribution because a full 4.0 distribution was not available to me, the year listed in the README is 1993. This example was clearly introduced in TASM 4.0 for this 4.0 feature.
    • T321 (u) - VERSION directive identifier for Turbo Assembler 3.21
      [bytepointer.com edit] an unknown/undocumented version?
    • T400 (u) - VERSION directive identifier for [the current] Turbo Assembler 4.0
  • Text Equate Substitution:
    TASM 4.0 has changed the way text equates are substituted since the TASM 3.0 version. This makes some TASM 3.0 code produce errors when assembled with TASM 4.0. To remedy this problem, do one of the following:
    1. Use the /UT300 command line directive to select TASM 3.0 style processing.
    2. Explicitly use the % text macro substitution operator at the start of lines that cause errors with TASM 4.0.
    [bytepointer.com edit] It is not clear if this change occured between 4.0 and 3.2 or another 3.x version.
  • Additional x86 privileged-mode Register Support

    • CR4 (u) - Used in protected mode to control operations such as virtual-8086 support, enabling I/O breakpoints, page size extension and machine check exceptions.
    • DR5 (u) - 32-bit "Debug Control" register (accessible in ring 0); obsolete synonym for DR7 register
  • Possible Undocumented-Feature Keywords:

    • FNLDENV (u) - [bytepointer.com edit] related to the FLDENV instruction (8087) ?
    • FNRSTOR (u) - [bytepointer.com edit] related to the FRSTOR instruction (8087) ?

TASM 4.0 Box Images
TASM 4.0 Box TASM 4.0 Box #2

TASM 4.1 © 1988, 1996 Borland International
TASM.EXE136,018 bytes (133k)md5=ff229c6cf0c77d7a112857ad6755e086date=2/21/1996 5:00am(bundled with TASM 5.0)[Command Line]
TASMX.EXE149,404 bytes (146k)md5=88c89dfb0a9b1179a7ec9f9f0655360cdate=2/21/1996 5:00am(bundled with TASM 5.0)[Command Line]
TASM32.EXE163,840 bytes (160k)md5=99adc798c3d15668b25a1986d7d1b117date=2/15/1994 6:33pm(date from patch file)[Command Line]
??version reports: 1034

The version 4.1 DOS assemblers were bundled with the version 5.0 retail box set. Since version 5.0 was only available as TASM32.EXE, Borland also bundled the latest DOS versions (4.1) for those who still needed TASM to run under DOS. THE CHANGELIST BELOW MOSTLY APPLIES TO THESE DOS ASSEMBLERS (TASM.EXE, TASMX.EXE) AND NOT THE TASM32 PATCHED VERSION ALSO DESCRIBED HERE! Binary analysis and empirical evidence shows the TASM32 (4.0 to 4.1) patched version does not have any of the keyword changes found in the DOS versions shipped with 5.0; in other words, the patched version is essentially TASM 4.0 with the long filename issue addressed.

This was the last version to support the TASM.EXE and TASMX.EXE DOS assemblers. I do not know if this version was distributed standalone, but it was likely distributed additionally as upgrade. Future official versions would only maintain the TASM32.EXE assembler.

One way to obtain the TASM 4.1 32-bit assembler was to upgrade the 4.0 TASM32.EXE using the patch found on the Borland C++ Technical Support page. The last known copy of this page on 6/17/2002 can be found HERE. The patch README, TA4P01.TXT, contained the description:
    Updates Turbo Assembler 4.0 for Chicago compatibility.
"Chicago" was the Microsoft codename for Windows 95. Borland's website description for the patch was:
    ta4p01.zip - Tasm 4.0 patch 1 (50KB). Fixes long filenames use under Win95
The descriptions above may have been all the patched version addressed, as it did not have any of the other keyword changes present in the DOS assemblers also displaying the version "4.1".

Like version 4.0, TASM32.EXE version 4.1 could not handle quoted filenames on the command line, despite the other filename changes addressed by the patch.

With exception of the "long filename" fixes described by Borland, the changelist information below was derived solely from binary analysis. Each keyword denoted by a "(u)" represents not only an undocumented change, but an undocumented feature. The T410 version identifier was mentioned in the TASM 5.0 User's Guide

  • DISTRIBUTED AS PATCH (TA4P01.ZIP) for version 4.0 TASM32.EXE
    LAST OFFICIAL DOWNLOAD LOCATION: ftp://ftp.inprise.com/pub/borlandcpp/devsupport/patches/tasm/ta4p01.zip
    OLDER DOWNLOAD LOCATION: ftp://ftp.borland.com/pub/techinfo/techdocs/language/tools/turboasm/ta4p01.zip
    REQUIREMENTS: RPatch 3.20 last officially available as ftp://ftp.inprise.com/pub/borlandcpp/devsupport/patches/bc5/patch.zip

    NOTE: All of the official download links are dead. RPatch 3.20 (PATCH.EXE) is needed to apply the patch above; it can be found in the TASMPT.ZIP package shown below for version 5.0r.
  • Long filename support for Windows 95 (Chicago)
  • Other Keywords Introduced:

    • T410 - VERSION directive identifier for [the current] Turbo Assembler 4.1
  • Possible Undocumented-Feature Keywords:

    • STACKALIGN (u)

    [bytepointer.com edit] The official manuals do not describe how exactly these keywords behave but the feature list found on the last working Lazy Assembler page (version 0.56 from 8/6/2007) describes them in their TASM implementation as "control of stack alignment with stackalign, stackunalign directives".

TASM 5.0 © 1988,1996 Borland International [Command Line]
TASM32.EXE184,320 bytes (180k)md5=870f03f5559b5437cb3637c8690ace10date=2/21/1996 5:00am
??version reports: 1280
Retail Price: $129.00

In this version, Borland finally added the features to bring TASM up to speed with the newer MASM 6.x syntax although it did so nearly 5 years after the release of MASM 6.0! In the process, TASM also failed to support near-100% MASM compatibility for this syntax that they had been famous for in the past. For example, there was no support for INVOKE (MASM's high-level call statement), the ADDR operator, etc. The TASM 5.0 User's Guide made the following statement:

Turbo Assembler in MASM mode is very compatible with MASM version 6.1. However, 100% compatibility is an ideal that can only be approached, since there is no formal specification for the language and different versions of MASM are not even compatible with each other.

I doubt a formal specification existed for the MASM syntax they were capable of emulating prior to MASM 6.x, but they did very well despite this. The fact is that Borland would not or could not devote the resources to make themselves near-100% MASM 6.x compatible. Unfortunately, the User's Guide also retained the following paragraph at the beginning of Chapter 3, which was no longer accurate:

For those of you struggling to make MASM do your bidding, this may be the most important chapter in the manual. In addition to near-perfect compatibility with MASM syntax, Turbo Assembler smooths the rough areas of assembly language programming with a MASM derivative we call Ideal mode.

The paragraph above was outdated as it was in reference to the MASM 5.1 and prior syntax (technically the 3.0 and 4.0 User's Guides say "very compatible with MASM 5.2", but 5.2 shouldn't count because that just meant Quick Assembler; the syntax was still 5.1).

The MASM 6.x syntax was good enough that it still lives on to this day, virtually unchanged, in each new version of MASM released by Microsoft. As of 2015, there have been at least 7 major versions of MASM starting with 7.0 that still use the same 6.x syntax and that will likely continue into the future. It might have done TASM some good to have matched this syntax (even to the extent that it did) sooner rather than later in version 5.0.

With that said, what TASM added in version 5.0 was HUGE. Had the high-level features not been added to TASM in its final major release (this version), the assembler they would have left to the world (and for C++Builder) would have been horribly outdated. TASM did come pretty close to the MASM 6.x syntax; close enough that it wasn't hard to convert source code between MASM and TASM, even if it could be a bit tedious.

This version was the last major release of TASM and the last version sold as a separate retail product. Turbo Assembler 5.0 last sold on the Borland US Online Shop as a classic product for $129.00; as of November 2006, the page was gone.

TASM 5.0 was exclusively a 32-bit protected mode assembler (TASM32.EXE) for Windows and would be into the future, although it retained the DPMI stub continuing to allow it to run under DOS provided you have the Borland Runtime Manager (32RTM.EXE) and the 32-bit DPMI server (DPMI32VM.OVL) in your path. The distribution did however include the previous DOS assemblers (TASM.EXE and TASMX.EXE) and linker (TLINK.EXE) from version 4.1.

One visual change new to the console output during assembly is the removal of the line "Remaining memory:" that had been present since 1.0:
Turbo Assembler  Version 5.0  Copyright (c) 1988, 1996 Borland International

Assembling file:   ver_dos.ASM
Error messages:    None
Warning messages:  None
Passes:            1
In contrast, note the console output for the prior version 4.1:
Turbo Assembler  Version 4.1  Copyright (c) 1988, 1996 Borland International

Assembling file:   ver_dos.ASM
Error messages:    None
Warning messages:  None
Passes:            1
Remaining memory:  452k
The changelist information below was derived from the TASM 5.0 User's Guide, binary analysis and the TSM_RDME.TXT (README). Each keyword denoted by a "(u)" was not officially documented.

Borland's Fact Sheet displayed the following blurb:
    Turbo Assembler 5.0 is a full featured stand-alone assembler. This product includes all the tools needed to create and debug assembly programs for 16 and 32 bit DOS and Windows platforms, including Windows 3.X, Win95, Win98, and NT. Some of the tools included are assemblers, linkers, console style debuggers, and resource compilers. Each of these tools comes in a 16 bit and a 32 bit version.

    C++Builder 5 Professional and Enterprise both include and integrate TASM32, the 32 bit assembler, with the IDE, allowing you to write or add inline assembly code or assembly sources to your 32bit Windows C/C++ projects. For building and debugging stand alone assembly programs for DOS and Windows, Turbo Assembler 5.0 is recommended.

    Create Fast Applications, Faster
    Order the world-standard Borland Turbo Assembler« and see how lightning-fast assembly speeds can turbocharge your turnaround times. In tests, the Borland Turbo Assembler proved itself up to 70% faster than other popular macro assemblers, with assembly speeds of up to 48,000 lines per minute! And it's versatile, with full Intel chip set support-from 8086 to Pentium.

    IDEAL for Beginners and Pros
    If you're just starting out in assembly language programming, Turbo Assembler's innovative IDEAL assembly mode will help you get productive faster and catch more errors sooner. And if you're a C++ professional, Turbo Assembler's advanced coding instructions will help you get the most from your assembly language programs. You'll especially like how Turbo Assembler's MASM compatibility mode lets you add new life to legacy code.

    • Up to 48,000 lines-per-minute assembly
    • Full 8088, 8086, 80286, 80386, i486, and Pentium support
    • IDEAL and MASM assembly modes
    • Interface support for C, C++, Pascal, FORTRAN, and COBOL
    • Multi-pass assembler with forward-reference resolution
    • Fast 16- and 32-bit Turbo Linker®
    • Turbo Debugger® for DOS and Windows
SYSTEM REQUIREMENTS / for a generic full installation (from TSM_INST.TXT):
  • 8 MB system memory (req. to run Win32)
  • Intel 386 or higher
  • DOS 5.01 or later
  • Windows 3.1 or later (to access Turbo Assembler help file)
  • Windows '95 or Windows NT (for targeting those environments)
  • Approximately 10 MB hard disk space
  • 3.5" High Density Disk Drive
SYSTEM REQUIREMENTS / from box top (see image below):
  • IBM PC-compatible PC running DOS 3.31 or higher
  • Minimum 2Mb memory and 1Mb disk space required for 16-bit development
  • Minimum 8Mb memory and 2Mb disk space required for 32-bit development
  • Thunk Compiler compatibility for Windows 95 flat thunking VIA the TASM32.EXE command-line option: -utthk
    The TASM 5.0 User's Guide refers you to the sample program and documentation: \EXAMPLES\THUNK95.TXT for more information on thunking.
    [bytepointer.com edit] This -utthk command-line option is not listed in the command-line help!

  • Enhanced compatibility for MASM 6.1

    • Data Declarations:

      Turbo Assembler now supports the use of type names as directives when defining variables. For example, the line:
         var DB 10
      can now be written as:
         var   BYTE 10
      The table below shows the type names and their equivalent directives.

      Type  Equivalent directive
    • New Signed Data Types:

      Type  Bytes  Value range
      SBYTE1-128 to +127
      SWORD2-32,768 to +32,767
      SDWORD4-2,147,483,648 to +2,147,483,647
    • New Floating-point Data Types:

      Type   Description   Bits   Significant digits   Approximate range
      REAL4Short real326-71.18 x 10-38 to 3.40 x 1038
      REAL8Long real6415-162.23 x 10-308 to 1.79 x 10308
      REAL1010-byte real80193.37 x 10-4932 to 1.18 x 104932

      Floating point constants can be designated as decimal constants or encoded hexadecimal constants, as shown in the following examples:
          ; Real decimal numbers
          dshort   REAL4       34.56       ;IEEE format
          ddouble  REAL8       3.456E1     ;IEEE format
          dtenbyte REAL10      3456.0E-2   ;10-byte format real format
          ; Hexadecimals, note the required trailing "r" and leading decimal digit
          hexshort       REAL4       4E700000r            ;IEEE short
          hexdouble      REAL8       4E70000000000000r    ;IEEE long
          hextenbyte     REAL10      4E776000000000000000r;10-byte real
    • New conditionals and looping directives:

      Turbo Assembler now supports several high level directives to permit program structures similar to those in higher level languages, such as C++ and Object Pascal. These directives generate code for loops and decisions, which are executed depending on the status of a conditional statement. The conditions are tested at run time, and can use the new run-time operators ==, !=, >=, <=, >, <, &&, ||, and !.


        The directives .IF, .ELSE, .ENDIF generate conditional jumps. If the expression following .IF evaluates to true, then the statements following the .IF are executed until an .ELSE (if any), .ELSEIF (if any), or .ENDIF directive is encountered. If the .IF expression evaluates to false, the statements following the .ELSE (if any) are executed until an .ENDIF directive is encountered. Use .ELSEIF to cause a secondary expression to be evaluated if the .IF expression evaluates to false.

        The syntax for the .IF directives is:
        .IF expression1
        [.ELSEIF expression2
          .IF bx == 16   ; if the value in bx equals 16
          mov   ax,20
          .ELSE          ; if the Value in bx does not equal 16
          mov   ax,30
      • .WHILE .ENDW

        The .WHILE directive executes the statements between the .WHILE and the .ENDW as long as the expression following .WHILE evaluates to true, or until a .BREAK directive is encountered. Because the expression is evaluated at the beginning of the loop, the statements within the loop will not execute at all if the expression initially evaluates to false. If a .CONTINUE directive is encountered within the body of the loop, control is passed immediately back to the .WHILE where the expression is re-evaluated. If .BREAK is encountered, control is immediately passed to the statement following the .ENDW directive.

        The syntax for the .WHILE directives is:
        .WHILE expression
          mov ax, 0               ; initialize ax to 0
          .WHILE ax < 128         ; while ax is less than 128
          mov dx, cx              ; put the value of cx in dx
          .IF dx == bx            ; if dx and bx are equal
          mov ax,dx               ; put the value of dx in ax
          .CONTINUE               ; re-evaluate .WHILE expression
          .ELSEIF ax == dx        ; if ax equals dx
          .BREAK                  ; break out of the .WHILE loop
          inc ax                  ; increment ax by 1
          .ENDW                   ; end of .WHILE loop

        The .REPEAT directive executes the statements between the .REPEAT and the .UNTIL as long as the expression following the .UNTIL (or .UNTILCXZ) evaluates to true, or until a .BREAK directive is encountered. Because the expression is evaluated at the end of the loop, the statements within the loop will execute at least once, even if the expression initially evaluates to false. If a .CONTINUE directive is encountered within the body of the loop, control is passed immediately to the .UNTIL where the expression is re-evaluated. If .BREAK is encountered, control is immediately passed to the statement following the .UNTIL (or .UNTILCXZ) directive. The .UNTIL directive generates conditional jumps. The .UNTILCXZ directive generates a LOOP instruction.

        The syntax for the .REPEAT directives is:
        .UNTIL expression
          mov ax, O              ; initialize ax to 0
          .REPEAT                ; while ax is less than 128
          inc ax                 ; increment by 1
          .UNTIL ax >= 128       ; end of .REPEAT loop

        As noted above, .BREAK and .CONTINUE can be used to alter the program flow within a loop. .CONTINUE causes the loop to immediately re-evaluate its expression, bypassing any remaining statements in the loop. .BREAK terminates the loop and passes control to the statement following the end of the loop. Both .BREAK and .CONTINUE can be combined with an optional .IF directive. If the .IF expression evaluates to true, the .BREAK or .CONTINUE are carried out, otherwise they are ignored.

          mov ax, bz
          .WHILE ax != cx
          .BREAK .IF ax == dx
          .CONTINUE .IF ax > dx
          inc ax
      • Logical "C-like" Operators:

        Operator  Meaning
        ==is equal to
        !=is not equal to
        >=is greater than or equal to
        <=is less than or equal to
        >is greater than
        <is less than
        &bit test
      • Flags in Conditions

        Turbo Assembler permits the use of flag values in conditions. The supported flag names are ZERO?, CARRY?, OVERFLOW?,SIGN?, and PARITY?. For example, to use the value of the CARRY flag in a loop expression, use:
        .WHILE (CARRY?)   ; if the CARRY flag is set...
    • Macro Repeat Blocks with Loop Directives

      Turbo Assembler supports "repeat blocks", or unnamed macros within a loop directive. The loop directive generates the statements inside the repeat block a specified number of times.

      • REPEAT loops:

        Use REPEAT to specify the number of times to generate the statements inside the macro. The syntax is:
          REPEAT constant
          number   LABEL BYTE     ; name the generated data
          counter = O             ; initialize counter
          REPEAT 128              ; repeat 128 times
             BYTE  counter        ; allocate a new number
             counter = counter + 1; increment counter
      • FOR loops:

        Use the FOR loop to iterate through a list of arguments, using the first argument the first time through, the second argument the second time through, and so on. The syntax is:
        FOR parameter,<argumentList>
        The parameter represents the name of each argument inside the FOR block. The argumentList is comma separated and enclosed in angle brackets.

          powers   LABEL BYTE
          FOR arg, <1,2,4,8,16,32,64,128>
             BYTE arg DUP (arg)
        The first iteration through the FOR loop sets arg to 1. The second iteration sets arg to 2. The third sets arg to 4, and so on. Text macros may be used in place of literal strings of values. The VARARG directive can be used in the argumentList to create a variable number of arguments.
      • FORC loops:

        FORC loops are almost identical to FOR loops, except that the argumentList is given a string, rather than as a comma separated list. The loop reads the string, character by character (including spaces), and uses one character per iteration. The syntax is:
          FORC parameter, <text>
        The parameter represents the name of each argument inside the FOR block. The text is a character string and enclosed in angle brackets.

          alphabet LABEL BYTE
             BYTE '&arg'    ; allocate letter
    • Text Macro Support:

      A string of characters can be given a symbolic name, and have that name used in the source code rather than the string itself. The named text is referred to as a text macro. Use the TEXTEQU directive to define a text macro. To assign a literal string to a text macro, enclose the string in angle brackets (<>). For example:
        myString TEXTEQU <This is my string>
      To assign one macro to another text macro, assign the macro name as in the example below:
        myString    TEXTEQU <This is my string>
        myNewString TEXTEQU myString           ;value of myString now in myNewString as well
      To assign a text representation of a constant expression to a text macro, precede the expression with a percent sign (%). For example:
        value TEXTEQU %(1 + num);assigns text representation of resolved expression to value
      Text macros are useful for naming strings of text that do not evaluate to integers. For example:
        pi      TEXTEQU  <3.14159>   ; floating point constant
        WPT     TEXTEQU  <WORD PTR>  ; keywords
        arg     TEXTEQU  <[bp+4]>    ; expression
    • New Directives:

      For MASM compatibility, Turbo Assembler now supports the directive STRUCT, EXTERN, and PROTO. These directives are synonyms for the STRUC, EXTRN, and PROCDESC directives, respectively.

      • ECHO directive:
        The ECHO directive displays its argument to the standard output device during assembly. It is useful for debugging purposes. The syntax is:
          ECHO argument
      • EXTERNDEF directive:
        Turbo Assembler treats EXTERNDEF as a PUBLIC declaration in the defining module, and as an external declaration in the referencing module(s). Use EXTERNDEF to make a variable or procedure common to two or more modules. If an EXTERNDEF variable or procedure is defined but not referenced in a given module, the EXTERNDEF is ignored; you need not create a symbol as you would using EXTERN. The syntax of the EXTERNDEF statement is:
          EXTERNDEF [langType] name : type
      • OPTION directive:

        The OPTION directive lets you make global changes to the behavior of the assembler. The basic syntax of the directive is:
          OPTION argument
        For example, to make the expression word size 16 bits, use the statement:
          OPTION EXPR16
        To make the expression word size 32 bits, use the statement:
          OPTION EXPR32
        The available options are listed below:

          NONE causes internal symbol recognition to be case sensitive, and causes the case of identifiers in the .OBJ file to be the same as specified in the EXTERNDEF,PUBLIC, or COMM statement.
          NOTPUBLIC (default) causes case insensitivity for internal symbol recognition and has the same behavior as NONE for identifiers in .OBJ files.
          ALL specifies universal case insensitivity and converts all identifiers to uppercase.
          Enables or disables the use of the dot (.) as the leading character in variable, macro, structure, union, and member names. The default is disabled.
          NOEMULATOR (default) tells the assembler to generate floating point math coprocessor instructions directly.
          EMULATOR generates floating point math instructions with special fixups for linking with a coprocessor emulator library.
        • EXPR16/EXPR32
          Sets the expression word size to 16 or 32 bits. The default is 32 bits.
        • LJMP/NOLJMP
          Enables or disables automatic conditional-jump lengthening. The default is enabled.
        • NOKEYWORD:<keywordList>
          Disables the keywords listed in keywordList. For example:
          Allows you to set the default PROC visibility as PRIVATE, PUBLIC, or EXPORT. The default is PUBLIC.
          SCOPED (the default) guarantees that all labels inside procedures are local to the procedure.
        • SEGMENT: USE16/USE32/FLAT
          Sets the global default segment size and the default address size for external symbols defined outside any segment.

        OPTION arguments for MASM 6.x Compatibility (Most only documented in the TASM 5.0 keyword changelist but no descriptions available; descriptions in this section were derived from MASM 6.1 Reference Guide unless stated otherwise):

        • .DOSSEG - MASM 6.0 equivalent for DOSSEG. TASM 5.0 User's Guide description: "Enables DOS segment-ordering at link time. Included for backward compatibility only."
        • .NOCREF - MASM 6.0 equivalent for .XCREF. Suppresses listing of symbols in the symbol table and browser file. If names are specified, only the given names are suppressed.
        • .NOLIST - MASM 6.0 equivalent for .XLIST. Suppresses program listing.
        • .SUBTITLE (u) - MASM 6.0 equivalent for SUBTTL. Specify subtitle for page (listing file)
        • .LISTALL - Starts listing of all statements. Equivalent to the combination of .LIST, .LISTIF, and .LISTMACROALL.
        • .LISTIF - Starts listing of statements in false conditional blocks.
        • .NOLISTIF - Suppresses listing of conditional blocks whose condition evaluates to false.
        • .LISTMACRO - Suppresses listing of macro expansions.
        • .LISTMACROALL - Starts listing of all statements in macros.
        • .NOLISTMACRO - Suppresses listing of macro expansions.
        • PROLOGUE - Instructs the assembler to call macroname to generate a user-defined prologue instead of generating the standard prologue code.
        • EPILOGUE - Instructs the assembler to call the macroname to generate a user-defined epilogue instead of the standard epilogue code when a RET instruction is encountered.
        • LANGUAGE - Specifies the default language type (C, PASCAL, FORTRAN, BASIC, SYSCALL, or STDCALL) to be used with PROC, EXTERN, and PUBLIC. This use of the OPTION directive overrides the .MODEL directive but is normally used when .MODEL is not given.
        • M510 - Sets all features to be compatible with MASM version 5.1, disabling the SCOPED argument and enabling OLDMACROS, DOTNAME, and, OLDSTRUCTS. OPTION M510 conditionally sets other arguments for the OPTION directive.
        • NOM510 - Disables M510 compatibility options
        • NOSIGNEXTEND - Overrides the default sign-extended opcodes for the AND, OR, and XOR instructions and generates the larger non-sign-extended forms of these instructions. Provided for compatibility with NEC V25 and NEC V35 controllers.
        • OFFSET - Determines the result of OFFSET operator fixups. SEGMENT sets the defaults for fixups to be segment-relative (compatible with MASM 5.1). GROUP, the default, generates fixups relative to the group (if the label is in a group). FLAT causes fixups to be relative to a flat frame. (The .386 mode must be enabled to use FLAT.)
        • OLDMACROS - Enables the version 5.1 treatment of macros.
        • NOOLDMACROS - Disables the version 5.1 treatment of macros.
        • OLDSTRUCTS - Enables compatibility with MASM 5.1 for treatment of structure members.
        • NOOLDSTRUCTS - Disables compatibility with MASM 5.1 for treatment of structure members.
        • READONLY - Enables checking for instructions that modify code segments, thereby guaranteeing that read-only code segments are not modified. Same as the /p command-line option of MASM 5.1, except that it affects only segments with at least one assembly instruction, not all segments. The argument is useful for protected mode programs, where code segments must remain read-only.
        • NOREADONLY - Disables checking for instructions that modify code segments
        • SETIF2 - If TRUE, .ERR2 statements and IF2 and ELSEIF2 conditional blocks are evaluated on every pass. If FALSE, they are not evaluated. If SETIF2 is not specified (or implied), .ERR2, IF2, and ELSEIF2 expressions cause an error. Both the /Zm command-line argument and OPTION M510 imply SETIF2:TRUE.
    • Visibility in Procedure Declarations:
      Turbo Assembler supports three visibility modes in procedure (PROC) declarations; PRIVATE, PUBLIC, and EXPORT. The visibility indicates whether the procedure is available to other modules. PUBLIC procedures are available to other modules. All procedures are PUBLIC by default. PRIVATE procedures are available only within the module in which they are declared. Code in other modules cannot call PRIVATE procedures. If the visibility is EXPORT, the linker places the procedure's name in the export table for segmented executables. EXPORT also enables PUBLIC visibility.
    • Distance in Procedure Declarations:
      In addition to the ability to specify NEAR or FAR distance in procedure (PROC) declarations, Turbo Assembler now supports the modifiers NEAR16, NEAR32, FAR16, and FAR32 when programming for the 80386, and up, and using both 16 and 32-bit segments.
    • SIZE operator in MASM mode:
      In MASM mode the size operator returns the values below for the given labels:

      Label  SIZE
  • Possible Undocumented-Feature Keywords:

    • FLDENVD (u) - [bytepointer.com edit] DWORD override version of the FLDENV instruction (8087)
    • FLDENVW (u) - [bytepointer.com edit] WORD override version of the FLDENV instruction (8087)
    • FNSAVED (u) - [bytepointer.com edit] DWORD override version of the FNSAVE instruction (8087)
    • FNSAVEW (u) - [bytepointer.com edit] WORD override version of the FNSAVE instruction (8087)
    • FNSTENVD (u) - [bytepointer.com edit] DWORD override version of the FNSTENV instruction (8087)
    • FNSTENVW (u) - [bytepointer.com edit] WORD override version of the FNSTENV instruction (8087)
    • FRSTORD (u) - [bytepointer.com edit] DWORD override version of the FRSTOR instruction (8087)
    • FRSTORW (u) - [bytepointer.com edit] WORD override version of the FRSTOR instruction (8087)
    • FSAVED (u) - [bytepointer.com edit] DWORD override version of the FSAVE instruction (8087)
    • FSAVEW (u) - [bytepointer.com edit] WORD override version of the FSAVE instruction (8087)
    • FSTENVD (u) - [bytepointer.com edit] DWORD override version of the FSTENV instruction (8087)
    • FSTENVW (u) - [bytepointer.com edit] WORD override version of the FSTENV instruction (8087)
    • IRETDF (u) - [bytepointer.com edit] 32-bit interrupt return with no epilogue generation (i.e. LEAVE instruction) (80386)
    • IRETF (u) - [bytepointer.com edit] interrupt return with no epilogue generation (i.e. LEAVE instruction) (80386)
    • LOOPED (u) - [bytepointer.com edit] DWORD override version of the LOOPE instruction (80386)
    • LOOPEW (u) - [bytepointer.com edit] WORD override version of the LOOPE instruction (80386)
    • LOOPNED (u) - [bytepointer.com edit] DWORD override version of the LOOPNE instruction (80386)
    • LOOPNEW (u) - [bytepointer.com edit] WORD override version of the LOOPNE instruction (80386)
    • LOOPNZD (u) - [bytepointer.com edit] DWORD override version of the LOOPNZ instruction (80386)
    • LOOPNZW (u) - [bytepointer.com edit] WORD override version of the LOOPNZ instruction (80386)
    • LOOPZD (u) - [bytepointer.com edit] DWORD override version of the LOOPZ instruction (80386)
    • LOOPZW (u) - [bytepointer.com edit] WORD override version of the LOOPZ instruction (80386)
    • PUSHD (u) - [bytepointer.com edit] DWORD override version of the PUSH instruction (80386)
    • PUSHW (u) - [bytepointer.com edit] WORD override version of the PUSH instruction (80386)

    New VERSION Directive Indentifiers:

    • M611 (u) - support for MASM 6.11
    • T410 (u) - support for Turbo Assembler 4.1
    • T450 (u) - [bytepointer.com edit] The presence of this keyword confirms that a TASM version 4.5 must have existed in some capacity, even if not released to the public. I've confirmed this VERSION id does indeed work, but what functionality it enables is a different story.
    • T500 - support for [the current] Turbo Assembler 5.0

TASM 5.0 Box Images
TASM 5.0 Box Front TASM 5.0 Box Left Side TASM 5.0 Box Right Side - Specs TASM 5.0 Box Back TASM 5.0 Box Top

TASM 5.0 Registration Card
TASM 5.0 Registration Card Front TASM 5.0 Registration Card Back
TASM 5.0 Disk #1
TASM 5.0 Disk #1

TASM 5.0 Manuals
TASM 5.0 User's Guide Manual TASM 5.0 Quick Reference Manual

* Complete and searchable copies of the manuals above are available on archive.org, courtesy of the bitsavers.org scan collection.
TASM 5.0 User's Guide (14MB)
TASM 5.0 Quick Reference (6.7 MB)

TASM 5.0r © 1988,1996 Borland International [Command Line]
TASM32.EXE188,416 bytes (184k)md5=e53a80ca8b18b138583e6fdc953def45date=2/5/1997 1:00am(date from TASM32.RTP (free download))
??version reports: 1280

This version was distributed as a patch with Borland's Debut product C++Builder 1.0 (Professional only). TASM 5.0 was incompatible with C++Builder and this patch made the necessary modifications (among other additions) so that TASM would function as the C++Builder's inline (or direct) assembler. This was the only known version of C++Builder that didn't distribute TASM.EXE outright, as you needed a copy of TASM 5.0 to apply the patch to. The C++Builder installation did not install TASM or the patch files, but rather the TASM patch was included on the CD distribution as an optional addition.

C++Builder was born from Delphi, Borland's largely successful and first Rapid Application Development (RAD) environment that was launched one year prior (2/14/1995). The primary difference between the two is that C++Builder employs a C++ syntax rather than the Object Pascal syntax employed by Delphi. C++Builder bears almost no resemblance to the development style and environment of Borland C++. Despite this, Borland officially named C++Builder as the successor to Borland C++ and discontinued Borland C++ (the world-renowned plain C++ product). On some retail boxes, C++Builder is called "The upgrade for Borland C++".

This version of TASM had initial support the Pentium MMX instruction set, although it wasn't finalized until version 5.2b. Intel released the MMX line of Pentium processors on 10/22/1996. Something curious about this version is that its new file size of 188,416 bytes did not change for over 15 years until Embarcadero added a digital signature to it. This was probably achieved by the future MMX and Pentium Pro support existing in this version, but disabled; and, a large amount of padding within the executable!

Intel Pentium MMX Processor

If you didn't have C++Builder 1.0 Professional, you could download the 5.0r patch for free from Borland's website. Borland's website included the following description:

Tasm 5.0 patch 1 (152KB). This patch will modify TD32.EXE and TASM32.EXE to support Borland C++Builder applications

The free patch contained the following files:
09/02/2002  05:00 AM               890 INSTALL.BAT
02/05/1996  04:07 PM            61,311 PATCH.EXE
04/11/1997  09:47 AM               832 README.TXT
02/05/1997  01:00 AM            48,705 TASM32.RTP
02/05/1997  01:00 AM            48,069 TD32.RTP
               5 File(s)        159,807 bytes
Likewise, the C++Builder 1.0 CD contained the patch files in the \TASM_TD directory:
02/09/1997  06:00 PM               855 INSTALL.BAT
02/05/1996  09:07 AM            61,311 PATCH.EXE
02/09/1997  06:00 PM            48,705 TASM32.RTP
02/09/1997  06:00 PM            48,069 TD32.RTP
               4 File(s)        158,940 bytes
Besides the different timestamps, the shared files between the two distributions were identical except for the INSTALL.BAT file. INSTALL.BAT from the free patch distribution had a 2002 date (indicating it was later modified) and had an odd CR CR LF line termination sequence rather than the standard CR LF sequence found in the same file dated 2/9/1997 on the C++Builder CD. Although the CR CR LF sequence was likely erroneous, it doesn't prevent INSTALL.BAT from functioning properly and is otherwise identical to the original. The only other change between the two distributions was that only the free patch contained the README.TXT file. The corresponding information on the C++Builder distribution could be located in the "Important Information" section in the README.HLP file:

If you are using TASM32.EXE directly, or if the source code you are compiling contains inline assembler statements, and you encounter an error such as :

[Linker Fatal Error] Fatal: Bad object file 'project1.cpp' near file offset 318d

you need to update your version of TASM32.EXE. To do so, run Install.BAT located in the \TASM_TD folder on the C++Builder installation CD. Install.BAT takes two parameters:

Install <C++Builder_Drive> <C++Builder_Folder>

For example, if you installed C++Builder in C:\CBUILDER, you would enter (be sure to include the backslash in the second parameter):

Install c: \cbuilder

Although the patch (TASM32.RTP) did work with the TASM 5.0 shipped in the standalone retail package, the patch distribution also included a Turbo Debugger patch (TD32.RTP) that did not work with the Turbo Debugger bundled in the same package. The Turbo Debugger may have already been "silently updated" (a common practice by Borland at the time). It is unclear which version of Turbo Debugger the patch was intended to work with. The latest and last version of Turbo Debugger was distributed for free from Borland's C++Builder Compiler promotional website as TurboDebugger.exe. Also available for free on this page was the Borland C++ compiler version 5.5.1 (and tools) distributed as freecommandLinetools.exe. This compiler and associated tools could be used standalone or as a drop-in replacement for the corresponding tools in the final version of Borland C++ 5.0 (with patches, the previous latest version of Borland C++ was 5.02). This page of "freebies" was taken down sometime between February and June of 2002, although you can still find these files available in various locations on the internet.

Like TASM version 3.2i, the command line displays the Serial/Tester line, indicating this was indeed a quick-fix (and internal) version:
Serial No:   Tester:
If the TASM32 binary is disassembled, the code that writes the text above to the console references two absolute addresses within the executable image to write both the serial number and tester strings. These addresses point to locations containing NULL characters appearing to be 9 and 26 bytes in length, respectively. They are conveniently located directly after the string "TESTERNAME" in the binary, which appears to have no other purpose in the assembler. My guess is that Borland may have had a tool that used the position of this identifier to insert the tester name and serial number directly into the executable binary for internal purposes.

The keyword changes below were derived solely from binary analysis and are denoted by a "(u)".

    LAST OFFICIAL DOWNLOAD LOCATION: http://www.borland.com/devsupport/borlandcpp/patches/TASMPT.ZIP
  • New Pentium MMX Directives and Version Identifier:
    • PMMX (u) - needed to assemble MMX instructions in this version
    • PNOMMX (u)
    • .MMX (u) - Borland commented out w/ space after period / doesn't work until 5.2b
    • .NOMMX (u) - Borland commented out w/ space after period / doesn't work until 5.2b
    • T510 (u) - VERSION directive identifier for Turbo Assembler 5.1
      [bytepointer.com edit] This is version 5.0r with a new version identifier (the latest embedded within file) that suggests we are at version 5.1. I think 5.0r is actually TASM 5.1, although I don't know of any TASM that reports itself as version 5.1 on the command-line.
  • New Pentium MMX Instructions:
    • EMMS (u)
    • MOVD (u)
    • MOVQ (u)
    • PACKSSWB (u)
    • PACKSSDW (u)
    • PACKUSWB (u)
    • PADDB (u)
    • PADDW (u)
    • PADDD (u)
    • PADDSB (u)
    • PADDSW (u)
    • PADDUSB (u)
    • PADDUSW (u)
    • PAND (u)
    • PANDN (u)
    • PCMPEQB (u)
    • PCMPEQW (u)
    • PCMPEQD (u)
    • PCMPGTB (u)
    • PCMPGTW (u)
    • PCMPGTD (u)
    • PMADDWD (u)
    • PMULHW (u)
    • PMULLW (u)
    • POR (u)
    • PSLLW (u)
    • PSLLD (u)
    • PSLLQ (u)
    • PSRAW (u)
    • PSRAD (u)
    • PSRLW (u)
    • PSRLD (u)
    • PSRLQ (u)
    • PSUBB (u)
    • PSUBW (u)
    • PSUBD (u)
    • PSUBSB (u)
    • PSUBSW (u)
    • PSUBUSB (u)
    • PSUBUSW (u)
    • PUNPCKHBW (u)
    • PUNPCKHWD (u)
    • PUNPCKHDQ (u)
    • PUNPCKLBW (u)
    • PUNPCKLWD (u)
    • PUNPCKLDQ (u)
    • PXOR (u)
  • New MMX Registers:
    • MM0 (u)
    • MM1 (u)
    • MM2 (u)
    • MM3 (u)
    • MM4 (u)
    • MM5 (u)
    • MM6 (u)
    • MM7 (u)
C++Builder 1.0
Standard Box
C++Builder 1.0 Box
C++Builder 1.0 Professional
CD and CD Case
C++Builder 1.0 Professional CD C++Builder 1.0 Professional CD Case Front C++Builder 1.0 Professional CD Case Back

C++Builder 1.0 Professional
Splash Image
C++Builder 1.0 Professional Splash Image
C++Builder 1.0 Professional
Programmer's Guide
C++Builder 1.0 Professional Programmer's Guide
C++Builder 1.0 TLINK32/ILINK32
Quick Reference
C++Builder 1.0 TLINK/TLINK32/ILINK32 Quick Reference

TASM 5.2b © 1988,1996 Borland International [Command Line]
tasm32.exe188,416 bytes (184k)md5=d4fdbb5dcd838328cd403f6a5684f8eedate=2/9/1998 3:00am
??version reports: 1282

This version appears to be a "beta" version of 5.2. This theory is supported by the command line displaying the Serial/Tester line (as in the previous version), and the fact that 5.2b actually predates version 5.2. I suspect that the "b" in the version means "beta".

This version finalized the MMX support that was added in the previous version 5.0r with the MASM-compatible .MMX directive and added some missing Pentium instructions. Additionally this version added support for the Pentium Pro (i686) processors, released by Intel on 11/1/1995, although it wouldn't have the FCOMI variant instructions until version 5.2.

It is important to note that C++Builder 3 is the successor to the first C++Builder (now known as 1.0). For reasons unknown, Borland did not release a C++Builder 2. C++Builder 3 was the first version to distribute TASM outright, but only in the Professional and Client/Server editions as shown in the C++Builder 3 Feature Matrix. Although the Standard Edition box is included in the images below, you can see by the features matrix on the side of its box that the Professional Edition includes TASM: "TASM for integrated assembly language performance". C++Builder requires TASM to process any 32-bit inline assembler code as this support was not built-in to the compiler.

Also included in the C++Builder 3 distribution, was the new incremental linker (ilink32.exe), "Turbo Incremental Link" at version 3.0. The older "Turbo Link" (tlink32.exe) version was also included, but by time C++Builder 4 (including TASM 5.2) was released, it had been phased out for the new linker.

C++Builder 3 Pro and Client/Server
C++Builder 3 Pro Box C++Builder 3 Client/Server Box
C++Builder 3 Standard Box
C++Builder 3 Standard Box Front C++Builder 3 Standard Box Left Side - Testimonials C++Builder 3 Standard Box Right Side - Features Matrix C++Builder 3 Standard Box Back

C++Builder 3 Professional Splash Image
C++Builder 3 Professional Splash Image

The keyword changes below were derived solely from binary analysis and are denoted by a "(u)".

  • New Pentium Pro Directives and Version Identifier:
    • .686 (u)
    • .686P (u)
    • .686C (u)
    • .687 (u)
    • P686 (u)
    • P686N (u)
    • P687 (u)
    • T520 (u) - VERSION directive identifier for [the current] Turbo Assembler 5.2
  • New MMX Directives:
    • .MMX (u)
    • .NOMMX (u)
  • New Pentium Instructions:
    • RDTSC (u)
  • New Pentium MMX Instructions:
    • RDPMC (u)
  • New Pentium Pro Instructions:
    • UD2 (u)
    • CMOVA (u)
    • CMOVAE (u)
    • CMOVB (u)
    • CMOVBE (u)
    • CMOVC (u)
    • CMOVE (u)
    • CMOVG (u)
    • CMOVGE (u)
    • CMOVL (u)
    • CMOVLE (u)
    • CMOVNA (u)
    • CMOVNAE (u)
    • CMOVNB (u)
    • CMOVNBE (u)
    • CMOVNC (u)
    • CMOVNE (u)
    • CMOVNG (u)
    • CMOVNGE (u)
    • CMOVNL (u)
    • CMOVNLE (u)
    • CMOVNO (u)
    • CMOVNP (u)
    • CMOVNS (u)
    • CMOVNZ (u)
    • CMOVO (u)
    • CMOVP (u)
    • CMOVPE (u)
    • CMOVPO (u)
    • CMOVS (u)
    • CMOVZ (u)
    • FCMOVB (u)
    • FCMOVE (u)
    • FCMOVBE (u)
    • FCMOVU (u)
    • FCMOVNB (u)
    • FCMOVNE (u)
    • FCMOVNBE (u)
    • FCMOVNU (u)

TASM 5.2 © 1988,1999 Inprise Corporation
TASM32.EXE188,416 bytes (184k)md5=a234cbe33e445f8eddc8ea91e3d2b7c8date=1/27/1999 4:00am[Command Line]
TASM32.EXE188,416 bytes (184k)md5=dc162d5df54ec99311ddaccffd0b3434date=11/29/2002 5:00am(from PSG Labs' 53PATCH.EXE)[Command Line]
??version reports: 1282

This version is believed to have been distributed with C++Builder 4 Professional and appears to be the last official version with changes (bugfixes and/or new features), excluding cosmetic changes.

This version finalized the Pentium Pro support added in the previous version 5.2b with the missing FCOMI variant instructions.

Intel Pentium MMX Processor Intel Pentium Pro (i686) Processor

In 1998, Borland changed its name to "Inprise". This was the first version bearing the new name and the last version of Turbo Assembler with new features.

Inprise Logo (Courtesy archive.org)
Inprise/Borland Logo

C++Builder 4
C++Builder 4 Professional Box C++Builder 4 Professional CD

C++Builder 4 Standard Splash Image
C++Builder 4 Standard Splash Image

There is also a PSG Labs patch (53PATCH.EXE shown above as the second TASM32.EXE) that transforms the formerly listed TASM32.EXE version 5.2 (in the header above) to the TASM32.EXE with the MD5 hash dc162d5df54ec99311ddaccffd0b3434; it claims to have all of the 5.3 features listed in the PSG Labs UNOFFICIAL CHANGELIST in the 5.3 section below, although it is listed here only because it still displays a command line identical to version 5.2 and reports the same @@version.

The keyword changes below were derived solely from binary analysis and are denoted by a "(u)".

  • New Pentium Pro Instructions:
    • FCOMI (u)
    • FCOMIP (u)
    • FUCOMI (u)
    • FUCOMIP (u)

TASM 5.3 © 1988, 2000 Inprise Corporation
TASM32.EXE188,416 bytes (184k)md5=e6e4dce5bf676419dab8ae09d312d0dfdate=1/30/2000 10:00pm(File Date bundled with C++Builder 5 Enterprise)[Command Line]
TASM32.EXE188,416 bytes (184k)md5=8016445b7c7fdddafdf8625ef9d36a35date=1/31/2000 12:00am(PSG Labs)[Command Line]
TASM32.EXE215,200 bytes (210k)md5=d92ff4066164e9bd6ebebbc080761c6edate=8/5/2002 5:00am(PSG Labs DOS32)[Command Line]
??version reports: 1283

The version first listed above (MD5 hash e6e4dce5bf676419dab8ae09d312d0df) was bundled with the following products:
  • C++Builder 5 (file date 1/30/2000 10:00pm)
  • C++Builder 6 (file date 1/31/2002 10:00pm)
  • Turbo Delphi Explorer (file date 8/5/2006 11:41am)
  • Turbo C++ Explorer (file date 9/8/2006 11:56am)
The Borland Developer Studio (predecessor to RAD Studio) was bundled with the short-lived line of revived "Turbo" products. The evaluation "Explorer" editions were Borland's attempt to compete with Microsoft's free Visual Studio Express Edition.

C++Builder 5 Enterprise C++Builder 6 Enterprise
C++Builder 5 Professional Box Front C++Builder 5 Enterprise Splash C++Builder 5 Enterprise About Box C++Builder 6 Enterprise Splash C++Builder 6 Enterprise About Box
Turbo C++ Explorer / 2006 Turbo Delphi Explorer / 2006
Turbo C++ Explorer 2006 Turbo Delphi Explorer 2006
C++Builder 5 Easter Egg Images C++Builder 6 Team Employees
C++Builder 5 Easter Eggs - Rampage Farmer C++Builder 5 Easter Eggs - Rampage Developers C++Builder 5 Easter Eggs - Rampage Eating Bill Gates C++Builder 5 Easter Eggs - Rampage Linux vs Seattle (Microsoft) C++Builder 6 Easter Eggs - C++Builder Team

NOTE: I couldn't resist including the easter-egg images (above) embedded in the Borland C++Builder 5 and 6 executables. These are allegedly images of the C++Builder team and many appearances of a creature known as "Borzilla". Information on how to activate these as well as many other easter eggs in the Borland products are described on Brian Long's site: C++Builder 5 Easter Eggs / C++Builder 6 Easter Eggs.

Stepan Polovnikov, the Russian developer who wrote Lazy Assembler (LZASM), a.k.a. PSG Labs, released a DOS extender version and a Win32 version of TASM32.EXE that reported 5.3, but it is not known if these files were official releases from Inprise or private hacks/fixes to an official release. PSG Labs also released a patch (53PATCH.EXE) to transform version 5.2 into 5.3 (see the 5.2 section above for details) claiming to have the features listed below. There is no official changelist information available on this version, but the PSG Labs changelist is provided below (with spelling errors fixed).

Besides bugfixes which may or may not have been official, this appears to have been the first version of TASM not to add any new features. It was also the first version (since the VERSION directive was introduced in TASM 3.0) where no new VERSION identifier was added. Following their convention, this version would have added the T530 keyword, but did not. This is further evidence that no new features were released, thus nothing for the VERSION directive to emulate.

If the official version did not include the fixes listed below, TASM 5.2 (the previous release) may have been the last version of Turbo Assembler to have any changes, beyond cosmetic that would only appear in later versions.

UPDATE: There is evidence that the changelist below only applies to the PSG Labs release. The long filename bug (1st changelist item below) when assembling multiple files using wildcards on the command line does indeed exist in the previous version, TASM 5.2. This bug does not appear when run with the PSG Labs TASM 5.3, but it remains in the official TASM 5.3 release. In fact, the bug exists even in the TASM 5.4 releases. This strongly suggests the latest and best TASM may in fact be the PSG Labs 5.3 release!

CHANGELIST (PSG Labs release):
  • support long file names for "tasm32 *"
  • assembling source filename begining with '´'
  • fix @Cpu symbol value for ".286p", ".386p", ".486p", ".586p", ".686p", "p286", "p386", "p486", "p586", "p686" directives
  • fix code generate for LOOPED & LOOPEW
  • enabled @@,@B,@F labels in IDEAL mode
  • support 2^32 labels for conditional directives
  • other bugs
REFERENCE: Phatcode (PSG Labs patches bundled with the TASM download)

TASM 5.4 © 1988, 2009 CodeGear [Command Line]
tasm32.exe188,416 bytes (184k)md5=78c9a9bfa1203745b08c0129e07053dbdate=1/14/2009 12:03pm(from C++Builder RAD Studio 2009)
??version reports: 1284

After January 2001, Inprise was renamed back to Borland. In 2006, Borland creates a division named CodeGear to manage the development tools products (C++Builder, Delphi, etc.). In 2007, the CodeGear division is sold to Embarcadero Technologies.

CodeGear Logos
CodeGear Logo #1 CodeGear Logo #2

This version has been distributed under the new CodeGear name with C++Builder since 2007, despite being owned by Embarcadero. As of 2009, the file size hasn't changed since 5.0r in 1996 (12 years). Binary analysis shows no keyword changes, but there were significant changes to the binary itself. I suspect these may have included changes to integrate TASM with current versions of C++Builder/RAD Studio. Unfortunately without official information, it is not known if these were indeed code/functionality changes or build-environment changes, possibly involving the use of different linking flags.

C++Builder 2009 Logo
C++Builder 2009 Logo

Very little is known about the changes to this version, although Wikipedia does have the following information:

TASM is still bundled with Embarcadero C++Builder and Delphi products. The current version (shipping with 2010 versioned products) is 5.4, Copyright 2009 to Codegear.
Unfortunately, Embarcadero's version 5.4 (4 November 2010) is virtually identical to Inprise's version 5.3 (30 May 2000) with the name of the company changed. Even the file sizes of the 5.3 and 5.4 are the same (188416 bytes). What was new in version 5.3 was the added MMX support. And nothing has changed since. By contrast, MASM version 6.15, dated 2 months earlier than TASM version 5.3, already supported not just MMX, but also 3DNow! and SSE. So, already in 2000 TASM lagged behind, and since then it has no longer really been developed

TASM 5.4 © 1988, 2010 Embarcadero Technologies, Inc. [Command Line]
tasm32.exe194,936 bytes (190k)md5=4ffa43fb80e81c962cee8521c6fe715adate=12/7/2013 4:55pm(from C++Builder RAD Studio12 XE5)
??version reports: 1284

Embarcadero eventually changed the branding once again, removing references to CodeGear and using their own name. This version continues to be supplied with C++Builder, including their free trial versions of RAD Studio.

Embarcadero Logos
Embarcadero 2010 Logo Embarcadero 2014 Logo

Since the previous 5.4 version (CodeGear), this is the first version I've seen with a digital signature: (Windows Explorer -> Properties). The digital signature is signed by "Embarcadero Technologies Inc." on "Friday, December 06, 2013 5:32:49 PM", but still no version resource block. Largely due to the new digital signature, the file size has increased about 6k. Besides superficial build environment changes, it can be assumed that the feature set has not changed and no bugs have been fixed.