flat assembler
Message board for the users of flat assembler.

Index > DOS > Enable unREAL by disabling AVX: fasm lite

Author
Thread Post new topic Reply to topic
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8351
Location: Kraków, Poland
Tomasz Grysztar 28 Nov 2019, 18:55
It has been a tradition for the DOS version of fasm to use unREAL mode when possible (with DPMI as only a safety fall-back). This, however, required code segment to fit in 65536 bytes, and fasm has broken that barrier a long time ago.

My temporary solution was to split the code into two segments, one for preprocessor stage and one for the main assembly stage. They share some of the code, thus the segments overlap, with the code needed in both stages being placed in the middle (and addressed only through relative jumps that work correctly in either segment).

But it stopped being enough in the 1.73 line. With the introduction of AVX-512 extensions the code of the assembly stage grew so much that it is no longer possible to fit it into that second segment. This switched a condition in the source text that causes the fasm to start relying exclusively on DPMI and the unREAL code is no longer there.

Therefore the only available option to get latest fasm working in unREAL mode is to remove some features. And since AVX family of extensions is the main offender, and AVX is not easily usable in DOS anyway, I have prepared a "lite" version for DOS, which does not include AVX.INC and removes the AVX-related entries from the tables with help of a few strategically placed macros:
Code:
; flat assembler lite interface for DOS
; Copyright (c) 1999-2019, Tomasz Grysztar.
; All rights reserved.

        format  MZ
        heap    0
        stack   8000h
        entry   main:start

include 'modes.inc'

segment main use16

start:

        mov     ax,ds
        mov     dx,[2Ch]
        push    cs cs
        pop     ds es
        mov     [psp_segment],ax
        mov     [environment_segment],dx

        mov     dx,_logo
        mov     ah,9
        int     21h

        cld

        call    go32
        use32

        call    get_params
        jc      information

        call    init_memory

        mov     esi,_memory_prefix
        call    display_string
        mov     eax,[memory_end]
        sub     eax,[memory_start]
        add     eax,[additional_memory_end]
        sub     eax,[additional_memory]
        shr     eax,10
        call    display_number
        mov     esi,_memory_suffix
        call    display_string

        xor     ah,ah
        int     1Ah
        mov     ax,cx
        shl     eax,16
        mov     ax,dx
        mov     [start_time],eax

        cmp     [mode],dpmi
        je      compile
        jmp     main+(first_segment shr 4):first_gate-first_segment

compile:
        and     [preprocessing_done],0
        call    preprocessor
        or      [preprocessing_done],-1
        call    parser
        call    assembler
        call    formatter

finish:
        call    display_user_messages
        movzx   eax,[current_pass]
        inc     eax
        call    display_number
        mov     esi,_passes_suffix
        call    display_string
        xor     ah,ah
        int     1Ah
        mov     ax,cx
        shl     eax,16
        mov     ax,dx
        sub     eax,[start_time]
        mov     ebx,100
        mul     ebx
        mov     ebx,182
        div     ebx
        or      eax,eax
        jz      display_bytes_count
        xor     edx,edx
        mov     ebx,10
        div     ebx
        push    edx
        call    display_number
        mov     ah,2
        mov     dl,'.'
        int     21h
        pop     eax
        call    display_number
        mov     esi,_seconds_suffix
        call    display_string
      display_bytes_count:
        mov     eax,[written_size]
        call    display_number
        mov     esi,_bytes_suffix
        call    display_string
        xor     al,al
        jmp     exit_program

information:
        mov     esi,_usage
        call    display_string
        mov     al,1
        jmp     exit_program

get_params:
        mov     [input_file],0
        mov     [output_file],0
        mov     [symbols_file],0
        mov     [memory_setting],0
        mov     [passes_limit],100
        mov     [definitions_pointer],predefinitions
        push    ds
        mov     ds,[psp_segment]
        mov     esi,81h
        mov     edi,params
    find_param:
        lodsb
        cmp     al,20h
        je      find_param
        cmp     al,'-'
        je      option_param
        cmp     al,0Dh
        je      all_params
        or      al,al
        jz      all_params
        cmp     [es:input_file],0
        jne     get_output_file
        mov     [es:input_file],edi
        jmp     process_param
      get_output_file:
        cmp     [es:output_file],0
        jne     bad_params
        mov     [es:output_file],edi
    process_param:
        cmp     al,22h
        je      string_param
    copy_param:
        stosb
        lodsb
        cmp     al,20h
        je      param_end
        cmp     al,0Dh
        je      param_end
        or      al,al
        jz      param_end
        jmp     copy_param
    string_param:
        lodsb
        cmp     al,22h
        je      string_param_end
        cmp     al,0Dh
        je      param_end
        or      al,al
        jz      param_end
        stosb
        jmp     string_param
    option_param:
        lodsb
        cmp     al,'m'
        je      memory_option
        cmp     al,'M'
        je      memory_option
        cmp     al,'p'
        je      passes_option
        cmp     al,'P'
        je      passes_option
        cmp     al,'d'
        je      definition_option
        cmp     al,'D'
        je      definition_option
        cmp     al,'s'
        je      symbols_option
        cmp     al,'S'
        je      symbols_option
    invalid_option:
        pop     ds
        stc
        ret
    get_option_value:
        xor     eax,eax
        mov     edx,eax
    get_option_digit:
        lodsb
        cmp     al,20h
        je      option_value_ok
        cmp     al,0Dh
        je      option_value_ok
        or      al,al
        jz      option_value_ok
        sub     al,30h
        jc      bad_params_value
        cmp     al,9
        ja      bad_params_value
        imul    edx,10
        jo      bad_params_value
        add     edx,eax
        jc      bad_params_value
        jmp     get_option_digit
    option_value_ok:
        dec     esi
        clc
        ret
    bad_params_value:
        stc
        ret
    memory_option:
        lodsb
        cmp     al,20h
        je      memory_option
        cmp     al,0Dh
        je      invalid_option
        or      al,al
        jz      invalid_option
        dec     esi
        call    get_option_value
        jc      invalid_option
        or      edx,edx
        jz      invalid_option
        cmp     edx,1 shl (32-10)
        jae     invalid_option
        mov     [es:memory_setting],edx
        jmp     find_param
    passes_option:
        lodsb
        cmp     al,20h
        je      passes_option
        cmp     al,0Dh
        je      invalid_option
        or      al,al
        jz      invalid_option
        dec     esi
        call    get_option_value
        jc      bad_params
        or      edx,edx
        jz      invalid_option
        cmp     edx,10000h
        ja      invalid_option
        mov     [es:passes_limit],dx
        jmp     find_param
    definition_option:
        lodsb
        cmp     al,20h
        je      definition_option
        cmp     al,0Dh
        je      bad_params
        or      al,al
        jz      bad_params
        dec     esi
        push    edi
        mov     edi,[es:definitions_pointer]
        call    convert_definition_option
        mov     [es:definitions_pointer],edi
        pop     edi
        jc      invalid_option
        jmp     find_param
    symbols_option:
        mov     [es:symbols_file],edi
      find_symbols_file_name:
        lodsb
        cmp     al,20h
        jne     process_param
        jmp     find_symbols_file_name
    param_end:
        dec     esi
    string_param_end:
        xor     al,al
        stosb
        jmp     find_param
    all_params:
        xor     al,al
        stosb
        pop     ds
        cmp     [input_file],0
        je      no_input_file
        mov     eax,[definitions_pointer]
        mov     byte [eax],0
        mov     [initial_definitions],predefinitions
        clc
        ret
    bad_params:
        pop     ds
    no_input_file:
        stc
        ret
    convert_definition_option:
        mov     ecx,edi
        xor     al,al
        stosb
      copy_definition_name:
        lodsb
        cmp     al,'='
        je      copy_definition_value
        cmp     al,20h
        je      bad_definition_option
        cmp     al,0Dh
        je      bad_definition_option
        or      al,al
        jz      bad_definition_option
        stosb
        inc     byte [es:ecx]
        jnz     copy_definition_name
      bad_definition_option:
        stc
        ret
      copy_definition_value:
        lodsb
        cmp     al,20h
        je      definition_value_end
        cmp     al,0Dh
        je      definition_value_end
        or      al,al
        jz      definition_value_end
        cmp     al,'\'
        jne     definition_value_character
        cmp     byte [esi],20h
        jne     definition_value_character
        lodsb
      definition_value_character:
        stosb
        jmp     copy_definition_value
      definition_value_end:
        dec     esi
        xor     al,al
        stosb
        clc
        ret

include '..\version.inc'

_logo db 'flat assembler  version ',VERSION_STRING,' lite',24h
_copyright db 'Copyright (c) 1999-2019, Tomasz Grysztar',0Dh,0Ah,0

_usage db 0Dh,0Ah
       db 'usage: fasm <source> [output]',0Dh,0Ah
       db 'optional settings:',0Dh,0Ah
       db ' -m <limit>         set the limit in kilobytes for the available memory',0Dh,0Ah
       db ' -p <limit>         set the maximum allowed number of passes',0Dh,0Ah
       db ' -d <name>=<value>  define symbolic variable',0Dh,0Ah
       db ' -s <file>          dump symbolic information for debugging',0Dh,0Ah
       db 0
_memory_prefix db '  (',0
_memory_suffix db ' kilobytes memory)',0Dh,0Ah,0
_passes_suffix db ' passes, ',0
_seconds_suffix db ' seconds, ',0
_bytes_suffix db ' bytes.',0Dh,0Ah,0

error_prefix db 'error: ',0
error_suffix db '.'
cr_lf db 0Dh,0Ah,0
line_number_start db ' [',0
line_data_start db ':',0Dh,0Ah,0
preprocessed_instruction_prefix db 'processed: ',0

include 'dpmi.inc'

align 16
first_segment:

include '..\preproce.inc'
include '..\parser.inc'
include '..\exprpars.inc'

align 16
second_segment:

include '..\exprcalc.inc'
include '..\errors.inc'
include '..\symbdump.inc'

include 'system.inc'

first_gate:
        and     [preprocessing_done],0
        call    preprocessor
        or      [preprocessing_done],-1
        call    parser
        jmp     main+(second_segment shr 4):second_gate-second_segment
first_segment_top = $ - first_segment

store_vex_instruction_code equ illegal_instruction

include '..\assemble.inc'
include '..\formats.inc'
include '..\x86_64.inc'

second_gate:
        call    assembler
        call    formatter
        jmp     main:finish

second_segment_top = $ - second_segment

if first_segment_top>=10000h | second_segment_top>=10000h
 if UNREAL_ENABLED>0
  UNREAL_ENABLED = -1
 else
  UNREAL_ENABLED = 0
 end if
else
 if UNREAL_ENABLED<0
  UNREAL_ENABLED = -1
 else
  UNREAL_ENABLED = 1
 end if
end if

macro db values&
{
        local CUT
        define __CUT CUT
        match name=,class=,id, values
        \{
                if name eqtype 'ax'
                        if class = 1Fh | ( class = 10h & ( id and 0F0h > 0C0h | id and 0E0h = 60h) )
                                __CUT = 1
                        end if
                end if
        \}
        if ~ defined __CUT
                db values
        end if
}
macro dw values&
{
        if values eqtype basic_instruction-instruction_handler & ~ defined values
                __CUT = 1
        else
                dw values
        end if
}

include '..\tables.inc'

purge db,dw

include '..\messages.inc'

align 4

include '..\variable.inc'

memory_setting dd ?
start_time dd ?
definitions_pointer dd ?
params rb 100h
predefinitions rb 100h

mode dw ?
real_mode_segment dw ?
displayed_count dd ?
last_displayed rb 2
preprocessing_done db ?

segment buffer

rb 1000h

assert first_segment_top<10000h & second_segment_top<10000h

macro display_hex value,bits
{
    repeat bits/4
        d = '0' + value shr (bits-%*4) and 0Fh
        if d > '9'
            d = d + 'A'-'9'-1
        end if
        display d
    end repeat
}

display 'first segment: '
display_hex first_segment_top,20
display 13,10,'second segment: '
display_hex second_segment_top,20
display 13,10    
Should I include it in the official DOS package? Smile
Post 28 Nov 2019, 18:55
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20299
Location: In your JS exploiting you and your system
revolution 28 Nov 2019, 22:07
Would it be possible to make call and jmp macros to generate near or far addresses automatically? Then the code could be any size.

Maybe Jcc would be tricky, but it can be converted into a Jncc/jmp combo.
Post 28 Nov 2019, 22:07
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8351
Location: Kraków, Poland
Tomasz Grysztar 29 Nov 2019, 06:53
The same machine code needs to run under DPMI with no segmentation, so no such tricks allowed.
Post 29 Nov 2019, 06:53
View user's profile Send private message Visit poster's website Reply with quote
CandyMan



Joined: 04 Sep 2009
Posts: 413
Location: film "CandyMan" directed through Bernard Rose OR Candy Shop
CandyMan 29 Nov 2019, 15:08
I've been using my own version with d3x dos extender for a long time.

You can download it from here:
https://board.flatassembler.net/topic.php?p=145936#145936

_________________
smaller is better
Post 29 Nov 2019, 15:08
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8351
Location: Kraków, Poland
Tomasz Grysztar 29 Nov 2019, 15:09
Yeah, but extender is not unREAL. Wink

To run fasm in protected mode my official recommendation is HX extender. It works great, and even gives you ability to run Win32 console versions of fasm and fasmg in DOS (this is how I run fasmg on my DOS machine; though I also have another option in Win32s).
Post 29 Nov 2019, 15:09
View user's profile Send private message Visit poster's website Reply with quote
guignol



Joined: 06 Dec 2008
Posts: 763
guignol 31 Dec 2019, 00:54
just as I thought that Tomasz improved his English...
Post 31 Dec 2019, 00:54
View user's profile Send private message Reply with quote
bubach



Joined: 17 Sep 2004
Posts: 341
Location: Trollhättan, Sweden
bubach 13 Jul 2020, 01:40
I stumbled onto this text file while roaming some dark forgotten corners of the web - which might be of some interest.
http://dgi_il.tripod.com/gemmis.txt

If I'm not confusing the issues here, the services mentioned goes under the name DOSX - or "Windows Global EMM Import Specification" & "Windows/386 Paging Import Specification". Relevant calls listed:

Code:
    Windows                    Memory Manager

 (a) INT 2Fh AX=1605h           Set device name to "EMMXXXX0".
                                Return mode-switch entry-point address.
     IOCTL-read "EMMXXXX0"      Return physical address of EMM import structure.
     Call mode-switch 
            entry-point (AX=0)
                                Set CPU to real mode.
Windows runs_

 (b) Set CPU to real mode
     Call mode-switch 
            entry-point (AX=1)  Setup the EMM import structure.
                                Regain protected mode.
     INT 2Fh AX=1606h           Restore device name.
    


And full C listing with example usage
Code:
/* dumping the EMM import structure */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <io.h>
#include <fcntl.h>
#include "emmimp.h"
#include "moveext.h"

#ifndef __TURBOC__
#define asm _asm
#endif

static int for_386max = 0;
static int raw_dump = 0;
static int machine;

static void emulate_win_init(uint16 ver, void (far **entryp)(void))
{
    void (far *entry)(void);

    asm push ds
    asm push es
    asm mov dx, 0
    asm mov ax, 0
    asm mov es, ax
    asm mov ds, ax
    asm mov di, ver
    asm mov si, 0
    asm mov cx, 0
    asm mov bx, 0
    asm mov ax, 1605h
    asm int 2fh
    asm mov word ptr entry, si
    asm mov word ptr entry + 2, ds
    asm pop es
    asm pop ds
    *entryp = entry;
}
static void emulate_win_term(void)
{
    asm mov ax, 1606h
    asm int 2fh
}
static uint32 get_emm_imp_addr(void)
{
    uint8 buf[6];
    int fd;

    fd = open("EMMXXXX0", O_RDONLY | O_BINARY);
    if (fd < 0) {
        printf("can't open EMMXXXX0\n");
        return 0;
    }
    memset(buf, 0, sizeof buf);
    buf[0] = 1;
    asm lea dx, word ptr buf
    asm mov cx, 6
    asm mov bx, fd
    asm mov ax, 4402h
    asm int 21h
    asm jc fail
    printf("emm import structure address:%08lx\n", *(uint32 *) buf);
    printf("emm import structure version:%d.%02d\n", buf[4], buf[5]);
    close(fd);
    return *(uint32 *) buf;
fail:
    printf("emm import struct address get failed\n");
    close(fd);
    return 0;
}
static void switch_to_real(void (far *entry)(void))
{
    asm push ds
    asm push es
    asm push di
    asm push si
    asm push bp
    asm mov ax, 0
    asm call dword ptr entry;
    asm pop bp
    asm pop si
    asm pop di
    asm pop es
    asm pop ds
}
static void switch_to_prot(void (far *entry)(void))
{
    asm push ds
    asm push es
    asm push di
    asm push si
    asm push bp
    asm mov ax, 1
    asm call dword ptr entry;
    asm pop bp
    asm pop si
    asm pop di
    asm pop es
    asm pop ds
}
static uint16 winver = 0x30a;   /* Windows version */
main(int ac, uint8 **av)
{
    void (far *entry)(void);
    int i;
    uint32 emm_imp_addr;
    static uint8 buf[8192];

    get_options(ac, av);    // not shown
    if (!for_386max)
        machine = machine_type();
    emulate_win_init(winver, &entry);
    if (!entry) {
        printf("illegal mode switch entry\n");
        emulate_win_term();
        return 1;
    }
    printf("mode switch entry:%08lx\n", entry);

    emm_imp_addr = get_emm_imp_addr();

    if (!emm_imp_addr) {
        emulate_win_term();
        return 1;
    }
    if (!for_386max) {
        disable();  /* disable interrupts while in real mode */
        switch_to_real(entry);
        switch_to_prot(entry);
        enable();   /* now Ok to enable interrupts */
        emulate_win_term();
        if (machine == MC_98)
            move_ext_mem_98(emm_imp_addr, buf, sizeof buf);
        else
            move_ext_mem_pc(emm_imp_addr, buf, sizeof buf);
        dump_emm_imp(emm_imp_addr, buf);
    } else {
        disable();
        switch_to_real(entry);
        move_ext_mem_real(emm_imp_addr, buf, sizeof buf);
        switch_to_prot(entry);
        enable();
        emulate_win_term();
        dump_emm_imp(emm_imp_addr, buf);
    }
    return 0;
}
    


Perhaps there's even more to it, hidden interrupts and whatnot. Interesting stuff either way.


Description:
Download
Filename: gemmis.txt
Filesize: 30.2 KB
Downloaded: 782 Time(s)

Description:
Download
Filename: gemmis.txt
Filesize: 30.2 KB
Downloaded: 747 Time(s)

Post 13 Jul 2020, 01:40
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.