; ---------------------------------------------------------------------------------------------------
; This is a file that modifies the behaviour of:
; flat assembler core
; Copyright (c) 1999-2007, Tomasz Grysztar.
; All rights reserved.

; Written by TNick, based on Tomasz Grysztar's SYMBDUMP.INC

; ---------------------------------------------------------------------------------------------------

; It should be included in FASM.ASM
; Modifications needed in core files:
;	- FASM.SAM: after the call to preprocessor, parser and assembler
;			call	preprocessor
;			call	parser
;			call	assembler
;		insert a call to ExportConst
;			call	ExportConst
;
;	- TABLES.INC: after this two lines
;			 db 6,'define'
;			 dw define_symbolic_constant-preprocessor
;		insert this:
;			 db 7,'expform'
;			 dw define_export-preprocessor
;		If there are other modifications to this table, the entry must be
;		inserted in alphabetical order.








; ==================================================================================================
;					DEFINITIONS
; ==================================================================================================


; structure of each entry that refers to a label. Places marked with Rn just tell that I don't
; know how that pice is used
	eLbL.Val	=	0 ; value of the label
	eLbL.R1		=	4
	eLbL.Flags	=	8 ; a combination of eLF bits
	eLbL.Reg1	=	12 ; first register used
	eLbL.Reg2	=	13 ; second register used
	eLbL.Op1	=	14 ; operation between Reg1 and Reg2 (if 1 => +, else *)
	eLbL.Pass	=	16 ; pass number where this label was defined
	eLbL.R4		=	18
	eLbL.R5		=	20
	eLbL.Name	=	24 ; pointer to name (string) of the label
	eLbL.R6		=	28
eLbL.size		=		32 ; THE SIZE of structure


; flags for eLbL.Flags
eLF.IdDef	=	0001b ; set if the label was defined
eLF.AsT		=	0100b ; set if this is an assembly time variable


; constants for ExportType variable.  
ET.None		=	0

; First byte is used to tell the format of output file:
ET.TyMask	=	0x0F
ET.Olly		=	0x01	; will export labels for Labelmaster plugin (format: hex_value <TAB> label <CRLF>)
ET.Incl		=	0x02	; will export labels in a include file (format: label = 0xhex_value)

; Second byte tells wheter you need all labels in output file or just those that were marked
ET.InMask	=	0xF0
ET.All		=	0x10	; export all
ET.Mark		=	0x20	; export only marked

; ==================================================================================================
;					VARIABLES
; ==================================================================================================

; controld the output file; 0 means nothing will be exported
ExportType	dd	0 ; this is set using <expform> directive

; address of output file [path\]name
ExpFile		dd	0 ; defaults to dfExpFile
ExpFileEnd	dd	0 ; address where ending 0 byte should be

; used for conversion
ConvAcs		db	"0123456789ABCDEF"

; this is the string that marks a label in source file
; if found, it is stripped and the label will be exported
; TODO: Maybe, in ET.All mode, we should skip these labels
ExpMarker	db	'E_X_P_O_R_T__1234567____________'
ExpMarker.zize	=	$ - ExpMarker

; default file name, if none provided with <expform> directive
dfExpFile	db	'LblExport.TXT',0	
dfExpFile.zize	=	$ - dfExpFile
		dd	0 ; when is to create the file, this dw is replaced with 0



; ==================================================================================================
;					CODE
; ==================================================================================================



; ---------------------------------------------------------------------------------------------------
; ARGUMENTS:	none
; RETURNS:	nothing
; DESCRIPTION:
;	This function must be called after the call to assembler and before the formatter. At this time
; all labels have definitive vslue. It will loop in list of labels and extract only relevant entries
; from there (skip anonymous and undefined symbols, assembly-time variables). The output is controlled
; by ExportType value (export in inc format or generate a file to be used with Labelmaster plugin
; for Olly. Also, if instructed, the function will extract only marked symbols.
ExportConst:
	
	; prezerve
	push	ebp
	push	edi
	
	
	; if we do not have a output file defined 'till now, use defaultg
	cmp	dword [ExpFile],	0
	jne	@F
		mov	dword [ExpFile],	dfExpFile
		mov	dword [ExpFileEnd],	(dfExpFile + dfExpFile.zize)
	@@:
	
	; place address for iteration in edx
	mov	ebp,			[ExportType]
	mov	edx,			[memory_end]
	
	; check to see if we're needed
	test	ebp,			ebp ; ET.None
	jz	.ExitF
	
	
; loop in symbols table
.dump_symbols:
	
	; did we reached the end of list?
	cmp	edx,			[labels_list]
	jbe	.symbols_dumped
	
	; reverse loop (get the pointer to previous entry
	sub	edx,			eLbL.size
	
	; do not dump anonymous symbols
	cmp	dword [edx+eLbL.Name],	0
	je	.dump_symbols
	
	; do not dump symbols that didn't get defined
	mov	ax,			[current_pass]
	test	byte [edx+eLbL.Flags],	eLF.IdDef
	jz	.dump_symbols
	
	; only from last pass
	cmp	ax,			[edx+eLbL.Pass]
	jne	.dump_symbols
	
	; do not dump assembly-time variables
	test	byte [edx+eLbL.Flags],	4
	jnz	.dump_symbols
	
	
	
	
	; isolate mark indicator 
	mov	eax,			ebp
	and	eax,			ET.InMask
	; pointer to the name
	mov	esi,			[edx+eLbL.Name]
	
	; should we export only marked symbols?
	cmp	eax,			ET.Mark
	; lenght of this name
	movzx	ebx,			byte [esi-1]
	jne	.SelectOutput
		
		; we only need marked symbols
		
		; search the marker in symbol's name
		push	edi
		mov	ecx,			ExpMarker.zize
		mov	edi,			ExpMarker
		repe	CMPSB
		pop	edi
		; if marker was not found skip this label
		jne	.dump_symbols 
		sub	ebx,			ExpMarker.zize
	
	
.SelectOutput:
	; esi now has the pointer to label's name (without the marker)
	; and ebx has it's lenght
	mov	eax,			ebp
	and	eax,			ET.TyMask
	cmp	eax,			ET.Olly
	je	.ExpOlly
	;jmp	.ExpIncl
	
	
; ============================================================

.ExpIncl: ; FORMAT: label <spc> = <spc> 0x<hex_value> <CRLF>
	
	; esi must point to name of the label
	; ebx must hold name's lenght
	
	; copy label name at current position (edi)
	mov	ecx,			ebx
	push	ecx
	rep	movsb
	pop	eax
	mov	ecx,			30h
	
	; try some sort of alignment
	sub	ecx,			eax
	mov	eax,			" "
	jbe	@F
		rep	stosb
	@@:
	stosb ; at least place a space after the name
	
	; insert equal
	mov	eax,			"= 0x"
	stosd
	
	; convert value of this label in string
	mov	ecx,			28
@@:	mov	eax,			[edx+eLbL.Val]
	shr	eax,			cl
	and	eax,			0x0F
	add	eax,			ConvAcs
	mov	al,			byte [eax]
	stosb
	sub	ecx,			4
	jnc	@B
	
	; start a new line
	mov	ax,			0A0Dh
	stosw
	
	jmp	.dump_symbols ; go find another
	
; ============================================================	
	
.ExpOlly: ; FORMAT: <hex_value> <tab> label <CRLF>
	
	; esi must point to name of the label
	; ebx must hold name's lenght

	
	; convert value of this label in string
	mov	ecx,			28
@@:	mov	eax,			[edx+eLbL.Val]
	shr	eax,			cl
	and	eax,			0x0F
	add	eax,			ConvAcs
	mov	al,			byte [eax]
	stosb
	sub	ecx,			4
	jnc	@B
	
	; insert a tab
	mov	al,			9
	stosb
	
	; copy label name at current position
	mov	ecx,			ebx
	rep	movsb
	
	; start a new line
	mov	ax,			0A0Dh
	stosw

	jmp	.dump_symbols
	
; ============================================================	
	
	
	
.symbols_dumped:
	; create the file where we write the output
	; since this naem may be in preprocessed area, where ending character may be a 1Ah
	; we prezerve the value and place a 0
	mov	ebp,			[ExpFileEnd]
	mov	edx,			[ExpFile]
	push	dword [ebp]
	mov	dword [ebp],		0
	call	create
	pop	dword [ebp]
	
	; compute the size to be witten and write
	mov	ecx,			edi
	; at [esp] is original edi value (at function entry)
	mov	edx,			[esp] ; !!! some other push'es may broke this
	
	sub	ecx,			edx
	jz	@F ; did we produced something?
	call	write
	
	; release the file handle
@@:	call	close
	
	
	
.ExitF:	
	; restore prezerved registers
	pop	edi
	pop	ebp
	ret
	
; END OF ExportConst
; ---------------------------------------------------------------------------------------------------
	
	
	
	

	
	
	
	
	
; ---------------------------------------------------------------------------------------------------
; ARGUMENTS:	none
; RETURNS:	nothing
; DESCRIPTION:
;	This is not exactly a function, since code is jumping here and from here...but is reusable...
; When this is called, esi points inside converted line, after the "ExpForm" keyword
; Purpose of thi is to extract the format requested by user (if reliable:) and store
; it in ExportType variable
define_export:
	
	; erase previously entered info, if any
	mov	dword [ExportType],		0
	mov	[ExpFile],			0
	
	; check first byte after the "ExpForm" keyword
	lods	byte [esi]
	
	; only keyword, without args? no export
	test	al,				al
	jz	.Req_None
	
	; something else than proper marker? error
	cmp	al,				1Ah
	jne	.InvalidArg
	
	; get the size of argument (not really needed for now)
	lods	byte [esi]
	mov	cl,				al
	; and see what's inthere
	lodsd
	
	; eax now has the type of export needed
	cmp	eax,				'none'
	je	.Req_None
	cmp	eax,				'incl'
	je	.Req_Include
	cmp	eax,				'olly'
	jne	.InvalidArg

; ----------------------------------------------------------------	
; set format of output file acording to user request
.Req_Olly:
	and	[ExportType],			(NOT ET.TyMask)
	or	[ExportType],			ET.Olly
	jmp	.Req_Type_Ok
	
.Req_None:
	and	[ExportType],			(NOT ET.TyMask)
	jmp	line_preprocessed
	
.Req_Include:
	and	[ExportType],			(NOT ET.TyMask)
	or	[ExportType],			ET.Incl
	;jmp	.Req_Type_Ok
.Req_Type_Ok:
	


; ----------------------------------------------------------------	
	
	
	; first after export type must be a 0 (no other args) of a ,
	; anything else is an error
	lods	byte [esi]
	
	; zero? default to include all in default file
	test	al,				al
	jz	.IncludeAllDefF

	cmp	al,				','
	jne	.InvalidArg
	
	
	; argument name (1a, size), a comma or a 0
	lods	byte [esi]
	
	test	al,				al
	jz	.IncludeAllDefF
	
	mov	ecx,				-1
	cmp	al,				','
	je	.IncludeAll
	
	cmp	al,				1Ah
	jne	.InvalidArg
	
	
	lods	byte [esi]
	movzx	ecx,				al
	mov	eax,				dword [esi]
	
	cmp	eax,				'all'
	je	.IncludeAll
	cmp	eax,				'all,'
	je	.IncludeAll
	cmp	eax,				'mark'
	jne	.InvalidArg
	
.IncludeMark:	
	and	[ExportType],			(NOT ET.InMask)
	or	[ExportType],			ET.Mark
	jmp	.Req_inc_Ok
.IncludeAll:
	and	[ExportType],			(NOT ET.InMask)
	or	[ExportType],			ET.All
	;jmp	.Req_inc_Ok
.Req_inc_Ok:
	add	esi,				ecx
	
	
	; first after paeameter must be a 0 (no other args) of a ,
	; anything else is an error
	lods	byte [esi]
	
	test	al,				al
	jz	.DefaultFile

	cmp	al,				','
	jne	.InvalidArg
	
	
	; argument name (1a, size), quoted (22, size) or a 0
	lods	byte [esi]
	test	al,				al
	jz	.DefaultFile
	
	cmp	al,				22h
	je	.QuotedF
	
	cmp	al,				1Ah
	jne	.InvalidArg
	
	; 1a entry => size is 1 byte long
	xor	eax,				eax
	lods	byte [esi]
	mov	dword [ExpFile],		esi
	add	eax,				esi
	mov	[ExpFileEnd],			eax
        jmp	line_preprocessed
	
	
.QuotedF:
	; 22 entry => size is 4 byts long
	lods	dword [esi]
	mov	dword [ExpFile],		esi
	add	eax,				esi
	mov	[ExpFileEnd],			eax
	jmp	line_preprocessed

	
.InvalidArg:
	pushad
	; display warning message to tell that there was an invalid keyword
	mov	esi,				.sErr_Arg
	call	display_string
	popad
	mov	dword [ExportType],		0
	jmp	line_preprocessed
.sErr_Arg	db	13,10,13,10,"WARNING!!! Invalid argument passed to ExpForm. Constants will not be exported!!!",13,10,13,10,0

.IncludeAllDefF:
	and	dword [ExportType],		(NOT ET.InMask)
	or	dword [ExportType],		ET.All
.DefaultFile:
	mov	dword [ExpFile],		dfExpFile
	mov	dword [ExpFileEnd],		(dfExpFile + dfExpFile.zize)
	jmp	line_preprocessed
; END OF define_export
; ---------------------------------------------------------------------------------------------------
