release 1.06

This commit is contained in:
Tomasz Grysztar 2000-08-23 12:00:00 +00:00
parent 8598d8f85a
commit 1dbd549eb7
15 changed files with 271 additions and 220 deletions

408
FASM.DOC
View file

@ -1,17 +1,17 @@
ÜÜÜ
Ûßßß ßÛ
ÛÛ
ÛÛ
Ü ÛÛÜÜ ÜßßßÛÜ ÜßßßßÜÞßÜÞßßÜßÛÝ
ÛÛ ÛÝ ÞÛ ß ÞÛ Û Ý
ÛÛ ÜßßßßßÛÛ ßßßÛÜÜ ÞÛ Û Ý
ÛÛ Û ÛÛ Ü ÞÛ ÞÛ Û Ý
ßßßßßß ßßßßß ßß ßßßßßß ß ß ß
ÜÜÜ
Ûßßß ßÛ
ÛÛ
ÛÛ
Ü ÛÛÜÜ ÜßßßÛÜ ÜßßßßÜÞßÜÞßßÜßÛÝ
ÛÛ ÛÝ ÞÛ ß ÞÛ Û Ý
ÛÛ ÜßßßßßÛÛ ßßßÛÜÜ ÞÛ Û Ý
ÛÛ Û ÛÛ Ü ÞÛ ÞÛ Û Ý
ßßßßßß ßßßßß ßß ßßßßßß ß ß ß
flat assembler version 1.05
flat assembler version 1.06
Copyright (c) 1999-2000, Tomasz Grysztar. All rights reserved.
Copyright (c) 1999-2000, Tomasz Grysztar. All rights reserved.
Table of Contents
@ -26,20 +26,20 @@ Table of Contents
2 Using flat assembler
2.1 Assembler syntax
2.1.1 Instruction syntax
2.1.1.1 Data access
2.1.1.2 Jumps and calls
2.1.1.3 Labels and constants
2.1.1.4 Addresses
2.1.1.5 Special cases
2.1.2 Number syntax
2.1.3 Logical expressions syntax
2.1.4 Defining constants
2.1.5 Defining data
2.1.1 Instruction syntax
2.1.1.1 Data access
2.1.1.2 Jumps and calls
2.1.1.3 Labels and constants
2.1.1.4 Addresses
2.1.1.5 Special cases
2.1.2 Number syntax
2.1.3 Logical expressions syntax
2.1.4 Defining constants
2.1.5 Defining data
2.2 Directives
2.2.1 Preprocessor directives
2.2.2 Code and format settings
2.2.3 Other directives
2.2.1 Preprocessor directives
2.2.2 Code and format settings
2.2.3 Other directives
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
@ -68,7 +68,8 @@ reccommended for best performance.
Other than an OS compatible with MSDOS 2.0+, fasm needs no other
software. Note that fasm will not run if the CPU is in protected or
V86 modes, since flat real mode cannot be entered in that case. The
fasmw needs to run an OS compatible with Win32.
fasmw needs to run an OS compatible with Win32, it may also be executed
under DOS using WDOSX extender.
1.4 Output formats
@ -76,7 +77,7 @@ fasmw needs to run an OS compatible with Win32.
fasm is a non-relocatable binary image such as a 'com' or 'sys' program.
Use of the directive 'format MZ' produces a relocatable and possibly
multi-segment 'exe' program. No extra 'linking' step is needed! Use of
the directive 'format PE' produces Win32 portable executable.
the directive 'format PE' produces portable executable.
1.5 Output file ordering
@ -116,40 +117,40 @@ beginning at the address of 'myvar'!
Unconditional:
jmp alpha ; simple jump
jmp near byte beta ; short jump
jmp near dword beta ; force dword size
jmp 10h:50h ; far jump
jmp 10h:dword 50000h ; 32-bit far jump
call far pword [1000h] ; 32-bit far call
call far dword [delta] ; 16-bit far call
call near dword [delta] ; 32-bit near call
jmp alpha ; simple jump
jmp near byte beta ; short jump
jmp near dword beta ; force dword size
jmp 10h:50h ; far jump
jmp 10h:dword 50000h ; 32-bit far jump
call far pword [1000h] ; 32-bit far call
call far dword [delta] ; 16-bit far call
call near dword [delta] ; 32-bit near call
Conditional:
je alpha ; will be optimized
jge byte alpha ; force byte (error if out of range)
jb dword alpha ; force dword (no optimization)
je alpha ; will be optimized
jge byte alpha ; force byte (error if out of range)
jb dword alpha ; force dword (no optimization)
2.1.1.3 Labels and constants
Examples of defining labels:
alpha: ; simple label
label beta ; as above
label gamma byte ; low byte of delta dword
delta dd 0 ; data label
epsilon = alpha + 1 ; constant definition
alpha: ; simple label
label beta ; as above
label gamma byte ; low byte of delta dword
delta dd 0 ; data label
epsilon = alpha + 1 ; constant definition
Local labels:
sigma:
.alpha: ; local label (1)
jmp .alpha ; jump to (1)
omega:
.alpha: ; local label (2)
jmp .alpha ; jump to (2)
jmp sigma.alpha ; jump to (1)
sigma:
.alpha: ; local label (1)
jmp .alpha ; jump to (1)
omega:
.alpha: ; local label (2)
jmp .alpha ; jump to (2)
jmp sigma.alpha ; jump to (1)
2.1.1.4 Addresses
@ -202,85 +203,58 @@ where it's used.
Data can be defined in two ways; if the data is to be initialised
to a specific value, the forms are:
gdtr db 16,0,0,0,0,0,0 ; sequence of bytes
attrib db 0x1E ; single byte (hexadecimal)
command: times 127 db 0 ; byte string
str001 db 'test.bin',0 ; character string
argv: times 10 dd 0 ; ten 32-bit double words
picture file 'star.gif' ; whole file contents
gdtr db 16,0,0,0,0,0,0 ; sequence of bytes
attrib db 0x1E ; single byte (hexadecimal)
command: times 127 db 0 ; byte string
str001 db 'test.bin',0 ; character string
argv: times 10 dd 0 ; ten 32-bit double words
picture file 'star.gif' ; whole file contents
Other forms available are:
dw ; 16-bit word
dp ; 48-bit pointer
dq ; 64-bit quad word
dt ; 80-bit floating point
dw ; 16-bit word
dp ; 48-bit pointer
dq ; 64-bit quad word
dt ; 80-bit floating point
If it is only desired to reserve space for data, the forms are:
_proname rd 1 ; reserve one dword
_inch rb 1 ; reserve one byte
newstack rd 255 ; reserve 255 dwords
_proname rd 1 ; reserve one dword
_inch rb 1 ; reserve one byte
newstack rd 255 ; reserve 255 dwords
Other forms available are:
rw ; 16-bit word
rp ; 48-bit pointer
rq ; 64-bit quad word
rt ; 80-bit floating point
rw ; 16-bit word
rp ; 48-bit pointer
rq ; 64-bit quad word
rt ; 80-bit floating point
Note that if the pre-defined 'times' macro is to be used to define
multiple data items, any label used must end with a colon. The other way is
to use 'label' directive before data definition, for example:
label argv dword
times 10 dd 0
label argv dword
times 10 dd 0
There's no struc directive in fasm, but you can do the same thing
using labeled macros:
macro pixel x,y,color
{
.x dw x
.y dw y
.color db color
}
mypix pixel 10,10,4
; so we have defined mypix.x, mypix.y and mypix.color variables
virtual at 0
virtpix pixel ?,?,?
end virtual
; and now also virtpix.x, virtpix.y, virtpix.color offsets
Preprocessor will insert macro label at the beginning of every symbol
starting with a single dot. This option should be used instead of standard
local labels mechanism, because it allows definition of structures inside
other structures. See 2.2.1 for more information about macros.
To handle cases, when one or more of macro params are empty (for
example just: 'mypix pixel'), you can write something like '.x dw x+0',
or use 'if <x> equ <>'.
To create union of some variables, you can use label directive with
'at <address>' phrase, or virtual directive, for example:
GDT_limit dw 15
GDT_address dd ?
GDT_limit dw 15
GDT_address dd ?
; now define virtual variable for lgdt and sgdt instructions
; now define virtual variable for lgdt and sgdt instructions
label GDTR pword at GDT_limit
label GDTR pword at GDT_limit
; and now the other method
; and now the other method
LDTR dp ?
LDTR dp ?
virtual at LDTR
LDT_limit dw ?
LDT_address dd ?
end virtual
virtual at LDTR
LDT_limit dw ?
LDT_address dd ?
end virtual
2.2 Directives
@ -289,92 +263,118 @@ or use 'if <x> equ <>'.
include - includes source file in source code before assembly
macro - defines macroinstructions, arguments are macro name and names
of macro arguments separated with commas, then '{' (start of macro)
character, macro instructions, and '}' (end of macro) character.
Here's an example of macroinstruction for data alignment:
of macro arguments separated with commas, then '{' (start of macro)
character, macro instructions, and '}' (end of macro) character.
Here's an example of macroinstruction for data alignment:
macro align value { rb (value-1) - ($ + value-1) mod value }
macro align value { rb (value-1) - ($ + value-1) mod value }
Macroinstructions may have empty arguments; to check if argument
is empty use something like 'if <argument> equ <>'.
If a macro is defined that uses an instruction with the same name
inside the macro definition, the previous meaning of this name is
used; useful redefinition of macros can be done in that way, for
example:
Macroinstructions may have empty arguments; to check if argument
is empty use something like 'if <argument> equ <>'.
If a macro is defined that uses an instruction with the same name
inside the macro definition, the previous meaning of this name is
used; useful redefinition of macros can be done in that way, for
example:
macro mov arg1,arg2
{
if (arg1 equ ds | arg1 equ es) & (arg2 equ ds | arg2 equ es)
push arg2
pop arg1
else
mov arg1,arg2 ; here original mov instruction will be used
end if
}
macro mov arg1,arg2,arg3
{
if <arg3> equ <>
mov arg1,arg2 ; here previous macro will be used
else
mov arg1,arg2
mov arg2,arg3
end if
}
mov ax,bx ; just 'mov ax,bx'
mov ds,es ; 'push es' and 'pop ds'
mov es,ds,dx ; 'push ds', 'pop es' and 'mov ds,dx'
macro mov arg1,arg2
{
if (arg1 equ ds | arg1 equ es) & (arg2 equ ds | arg2 equ es)
push arg2
pop arg1
else
mov arg1,arg2 ; here original mov instruction will be used
end if
}
macro mov arg1,arg2,arg3
{
if <arg3> equ <>
mov arg1,arg2 ; here previous macro will be used
else
mov arg1,arg2
mov arg2,arg3
end if
}
mov ax,bx ; just 'mov ax,bx'
mov ds,es ; 'push es' and 'pop ds'
mov es,ds,dx ; 'push ds', 'pop es' and 'mov ds,dx'
But note that using these macros in big programs will dramatically
slow down assembly (up to 4 times!) and increase memory requirements.
But note that using these macros in big programs will dramatically
slow down assembly (up to 4 times!) and increase memory requirements.
If you type arguments in brackets, macroinstruction will allow
multiple groups of arguments, and will repeat all instructions for
each arguments group separately. For example:
If you type arguments in brackets, macroinstruction will allow
multiple groups of arguments, and will repeat all instructions for
each arguments group separately. For example:
macro stoschar [char]
{
mov al,char
stosb
}
macro stoschar [char]
{
mov al,char
stosb
}
stoschar 1,2,3,4 ; store four bytes at es:di
stoschar 1,2,3,4 ; store four bytes at es:di
Also macroinstruction can be divided into parts, each beginning
with '{', and ending with '}' character. Each macroinstruction part
will be processed for all groups of arguments before processing next
part. Local symbol defined in one of parts will be available in all
next parts, when processing the same group of arguments.
For example, to create table of addresses to strings, and then
strings data, use this macro:
Also macroinstruction can be divided into parts, each beginning
with '{', and ending with '}' character. Each macroinstruction part
will be processed for all groups of arguments before processing next
part. Local symbol defined in one of parts will be available in all
next parts, when processing the same group of arguments.
For example, to create table of addresses to strings, and then
strings data, use this macro:
macro strtbl [string]
{ local label
dd label }
{ label db string,0 }
macro strtbl [string]
{ local label
dd label }
{ label db string,0 }
struc - this is the variant of macro directive used to create data
structures. When struc macro is used in program, it must be preceded
by a label. Preprocessor will insert this label at the beginning of
every symbol starting with a single dot. For example:
struc pixel x,y,color
{
.x dw x
.y dw y
.color db color
}
mypix pixel 10,10,4
; so we have defined mypix.x, mypix.y and mypix.color variables
virtual at 0
pixel pixel ?,?,?
end virtual
; and now also pixel.x, pixel.y, pixel.color offsets
To handle cases, when one or more of macro params are empty (for
example just: 'mypix pixel'), you can write something like
'.x dw x+0', or use 'if <x> equ <>'.
local - used inside macro definitions, defines local symbols, which
will have unique names in every macro call; arguments are local
symbol names, separated with commas.
will have unique names in every macro call; arguments are local
symbol names, separated with commas.
purge - argument is one or more macro names, separated with commas; this
directive will remove last definition of specified macro; for example
when you've redefined some macro, you can get previous definition
back using purge (it's different than TASM in this respect; there
purge eliminates all macros of that name). If the macro has not been
defined, you won't get any error (exactly like in TASM).
When you need do totally undefine some non-preprocessor symbol
(defined with equ, or labels), use this clever macro:
directive will remove last definition of specified macro; for example
when you've redefined some macro, you can get previous definition
back using purge (it's different than TASM in this respect; there
purge eliminates all macros of that name). If the macro has not been
defined, you won't get any error (exactly like in TASM).
When you need do totally undefine some non-preprocessor symbol
(defined with equ, or labels), use this clever macro:
macro undefine symbol
{
local undefined
symbol equ undefined
}
macro undefine symbol
{
local undefined
symbol equ undefined
}
For example after 'undefine add', you can't use 'add' instruction,
but definition and usage of 'add' label is possible. Also, if you
use '_add equ add', and then 'undefine add', you can define 'add'
label and have access to 'add' instruction using '_add' symbol.
For example after 'undefine add', you can't use 'add' instruction,
but definition and usage of 'add' label is possible. Also, if you
use '_add equ add', and then 'undefine add', you can define 'add'
label and have access to 'add' instruction using '_add' symbol.
equ - defines symbolic constant.
@ -388,33 +388,33 @@ org - argument must be an address value; set from what address this
code will start in memory.
format - set output file format, can be set binary, MZ or PE; binary
is the default format, MZ is an EXE file format, PE is a portable
executable file format. When specified format is PE, more format
settings can follow; use 'console' or 'GUI' words to set target
subsystem type, 'i386', 'i486' or 'i586' to specify target machine
type, 'DLL' to create dynamic link library.
is the default format, MZ is an EXE file format, PE is a portable
executable file format. When specified format is PE, more format
settings can follow; use 'console' or 'GUI' words to set target
subsystem type, 'i386', 'i486' or 'i586' to specify target machine
type, 'DLL' to create dynamic link library.
label - define label, needed argument is a name of label, optional
arguments are size of label and 'at <address>' phrase.
arguments are size of label and 'at <address>' phrase.
segment - define segment at current position (only in MZ format),
code will be aligned to paragraph. In segment definition, after
segment name, 'use16' or 'use32' is allowed.
code will be aligned to paragraph. In segment definition, after
segment name, 'use16' or 'use32' is allowed.
section - define section at current position (only in PE format), code will
be aligned to page (4096 bytes). First argument is a string
containing section name, optional next arguments are section type
(code, data, udata, import, export, resource), and section
attributes (readable, writeable, executable, shareable).
be aligned to page (4096 bytes). First argument is a string
containing section name, optional next arguments are section type
(code, data, udata, import, export, resource), and section
attributes (readable, writeable, executable, shareable).
entry - define program entry point (only in MZ and PE formats). In MZ format
argument must be a segment:offset address (like in far jump).
argument must be a segment:offset address (like in far jump).
stack - define program stack size (only in MZ and PE formats), when no stack
is defined, default size of 1000h bytes is used. In MZ format the
stack location can be defined in segment:offset form. In PE format
second argument is allowed to define stack commit (first argument
defines stack reserve).
is defined, default size of 1000h bytes is used. In MZ format the
stack location can be defined in segment:offset form. In PE format
second argument is allowed to define stack commit (first argument
defines stack reserve).
heap - define 'heap' size in paragraphs (only in MZ and PE formats). In MZ
format argument is a 16-bit value, defining maximum size of additional
@ -427,21 +427,21 @@ heap - define 'heap' size in paragraphs (only in MZ and PE formats). In MZ
2.2.3 Other directives
times - repeat instruction n times; arguments are number of repeats and
instruction to repeat (optionally character ':' can be used to
separate number and instructions), also % value (current repeat
number) can be used in instruction, so 'times 5 db %' will create
01,02,03,04,05 bytes; recurrency is also allowed, so
'times 3 times % db %' will create 01,01,02,01,02,03 bytes.
instruction to repeat (optionally character ':' can be used to
separate number and instructions), also % value (current repeat
number) can be used in instruction, so 'times 5 db %' will create
01,02,03,04,05 bytes; recurrency is also allowed, so
'times 3 times % db %' will create 01,01,02,01,02,03 bytes.
repeat - larger version of times directive, repeat has one argument -
number of repeats, instructions to repeat are expected in next
lines, ended with 'end repeat' directive.
number of repeats, instructions to repeat are expected in next
lines, ended with 'end repeat' directive.
virtual - creates virtual code or data at specified address; this data
won't be included in output file, but labels defined there can
be useful in other parts of program; argument to virtual is
'at <address>' phrase, virtual instructions are expected in
next lines, ended with 'end virtual' directive.
won't be included in output file, but labels defined there can
be useful in other parts of program; argument to virtual is
'at <address>' phrase, virtual instructions are expected in
next lines, ended with 'end virtual' directive.
if - used to assemble some part of codes, when specified conditions are
met; argument is a logical expression, in next lines instructions to

View file

@ -1,5 +1,5 @@
flat assembler version 1.05
flat assembler version 1.06
Copyright (c) 1999-2000, Tomasz Grysztar
All rights reserved.

View file

@ -1,5 +1,5 @@
; flat assembler version 1.05
; flat assembler version 1.06
; Copyright (c) 1999-2000, Tomasz Grysztar
; All rights reserved.

View file

@ -1,5 +1,5 @@
; flat assembler version 1.05
; flat assembler version 1.06
; Copyright (c) 1999-2000, Tomasz Grysztar
; All rights reserved.

View file

@ -1,5 +1,5 @@
; flat assembler version 1.05
; flat assembler version 1.06
; Copyright (c) 1999-2000, Tomasz Grysztar
; All rights reserved.

View file

@ -1,5 +1,5 @@
; flat assembler version 1.05
; flat assembler version 1.06
; Copyright (c) 1999-2000, Tomasz Grysztar
; All rights reserved.
;
@ -177,7 +177,7 @@ include 'tables.inc'
_copyright db 'Copyright (c) 1999-2000, Tomasz Grysztar',24h
_logo db 'flat assembler version 1.05',0Dh,0Ah,24h
_logo db 'flat assembler version 1.06',0Dh,0Ah,24h
_usage db 'usage: fasm source output',0Dh,0Ah,24h
_passes_suffix db ' passes, ',24h

View file

@ -1,5 +1,5 @@
; flat assembler version 1.05
; flat assembler version 1.06
; Copyright (c) 1999-2000, Tomasz Grysztar
; All rights reserved.

View file

@ -1,5 +1,5 @@
; flat assembler version 1.05
; flat assembler version 1.06
; Copyright (c) 1999-2000, Tomasz Grysztar
; All rights reserved.

View file

@ -1,5 +1,5 @@
; flat assembler version 1.05
; flat assembler version 1.06
; Copyright (c) 1999-2000, Tomasz Grysztar
; All rights reserved.
@ -247,9 +247,19 @@ preprocess_instruction:
je .skip_file
movzx ecx,byte [edi]
inc edi
and cl,7Fh
mov ebx,edi
add ebx,ecx
add ebx,5
test byte [edi-1],80h
jnz .struc
cmp [macro_struc_name],0
jne .skip_macro
jmp .compare
.struc:
cmp [macro_struc_name],0
je .skip_macro
.compare:
cmp ecx,ebp
jne .skip_macro
mov edx,esi
@ -347,7 +357,12 @@ include_file:
add esp,4
pop esi ecx
ret
define_struc:
mov [macro_struc],1
jmp macro_definition
define_macro:
mov [macro_struc],0
macro_definition:
call skip_spaces
lods byte [esi]
cmp al,27h
@ -379,9 +394,20 @@ define_macro:
je .skip_file
movzx ecx,byte [edi]
inc edi
and cl,7Fh
mov ebx,edi
add ebx,ecx
add ebx,5
test byte [edi-1],80h
jnz .struc
cmp [macro_struc],0
jne .skip_macro
jmp .compare
.struc:
and cl,7Fh
cmp [macro_struc],0
je .skip_macro
.compare:
cmp ecx,ebp
jne .skip_macro
mov edx,esi
@ -403,6 +429,13 @@ define_macro:
mov ebp,esi
xchg ebp,[edi+1]
mov esi,edx
mov al,[ebx]
shr al,7
xchg al,[macro_struc]
and byte [ebx],7Fh
or al,al
jz create_macro
or byte [ebx],80h
jmp add_macro
create_macro:
xor ebp,ebp
@ -429,8 +462,12 @@ define_macro:
mov edi,edx
sub edx,[additional_memory]
dec edx
cmp edx,100h
cmp edx,80h
jae name_too_long
cmp [macro_struc],0
je macro_name_length_ok
or dl,80h
macro_name_length_ok:
mov [ebx],dl
lea ebx,[edi+5]
mov [additional_memory],ebx
@ -1270,6 +1307,7 @@ names_list dd ?
macro_defined db ?
macro_directive_allowed db ?
macro_instructions dd ?
macro_struc db ?
macro_struc_name dd ?
macro_struc_name_size dw ?
multi_macro_current dw ?

View file

@ -1,5 +1,5 @@
; flat assembler version 1.05
; flat assembler version 1.06
; Copyright (c) 1999-2000, Tomasz Grysztar
; All rights reserved.

View file

@ -1,5 +1,5 @@
; flat assembler version 1.05
; flat assembler version 1.06
; Copyright (c) 1999-2000, Tomasz Grysztar
; All rights reserved.
@ -363,6 +363,8 @@ preprocessor_directives:
dw include_file-preprocessor
db 5,'macro'
dw define_macro-preprocessor
db 5,'struc'
dw define_struc-preprocessor
db 5,'purge'
dw purge_macro-preprocessor
db 0

View file

@ -1,5 +1,5 @@
; flat assembler version 1.05
; flat assembler version 1.06
; Copyright (c) 1999-2000, Tomasz Grysztar
; All rights reserved.

View file

@ -1,5 +1,5 @@
; flat assembler version 1.05
; flat assembler version 1.06
; Copyright (c) 1999-2000, Tomasz Grysztar
; All rights reserved.
;
@ -181,7 +181,7 @@ include '..\tables.inc'
_copyright db 'Copyright (c) 1999-2000, Tomasz Grysztar',0
_logo db 'flat assembler version 1.05',0Dh,0Ah,0
_logo db 'flat assembler version 1.06',0Dh,0Ah,0
_usage db 'usage: fasm source output',0Dh,0Ah,0
_passes_suffix db ' passes, ',0

View file

@ -1,5 +1,5 @@
; flat assembler version 1.05
; flat assembler version 1.06
; Copyright (c) 1999-2000, Tomasz Grysztar
; All rights reserved.

View file

@ -2,13 +2,20 @@
Questions or comments please send to:
grysztar@omega.im.uj.edu.pl
version 1.06
[23-08-2000]
------------
[+] struc directive instead of labeled macros
version 1.05
[16-08-2000]
------------
[-] fixed some bugs with PE format
[+] numeric constants redefinition allowed
[+] labeled macroinstructions
version 1.04
[10-08-2000]
------------
[+] PE output format support
[+] Win32 version of fasm executable
@ -18,19 +25,23 @@ version 1.04
[-] many other fixes and improvements
version 1.03
[19-07-2000]
------------
[-] more bugs fixed
[+] allowed empty labels to separate local symbols
version 1.02
[06-07-2000]
------------
[-] minor bugs fixed
[+] some documentation changes
version 1.01
[01-07-2000]
------------
[-] fixed bug in MZ header generator
version 1.00
[19-06-2000]
------------
[+] first serious release