News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

CALL instruction with opcode 9Ah

Started by habran, April 23, 2019, 11:08:40 PM

Previous topic - Next topic

habran

Does anyone know how to write assembler code to invoke these instructions:
CALL ptr16 : 16   9A cd
CALL ptr16 : 32   9A cp
Defuze accept this:

call        0x002A:0x00000018 
call        0x2824:0x0003CBF6

and produces this:

0:  9a 18 00 00 00 2a 00    call   0x2a:0x18
7:  9a f6 cb 03 00 24 28    call   0x2824:0x3cbf6

UASM refuses to assemble it
but when I use :

db 0x9a, 0x18, 0x00, 0x00, 0x00, 0x2a, 0x00
db 0x9a, 0xf6, 0xcb, 0x03, 0x00, 0x24, 0x28

MSVC disassembles to this:

01051062 9A 18 00 00 00 2A 00 call        002A:00000018 
01051069 9A F6 CB 03 00 24 28 call        2824:0003CBF6
Cod-Father

hutch--

Best I can find is in the Intel manual.

9A cd CALL ptr16:16 D Invalid Valid Call far, absolute, address given in operand.
9A cp CALL ptr16:32 D Invalid Valid Call far, absolute, address given in operand.

Valid only in legacy mode, not 64 bit.

nidud

#2
deleted

habran

Thanks both of you, however, it looks to me that nobody ever used it in asm programming ::)
why did intel bother to create these instructions :dazzled:
Cod-Father

K_F

Quote from: habran on April 24, 2019, 05:21:19 AM
why did intel bother to create these instructions :dazzled:
For undocumented 'secrets' maybe.. -- the paranoid spying world ;)
'Sire, Sire!... the peasants are Revolting !!!'
'Yes, they are.. aren't they....'

LiaoMi

9A  cd    CALL ptr16:16    17+m,pm=34+m   Call intersegment, to full
                                          pointer given
9A  cd    CALL ptr16:16    pm=52+m        Call gate, same privilege
9A  cd    CALL ptr16:16    pm=86+m        Call gate, more privilege, no
                                          parameters
9A  cd    CALL ptr16:16    pm=94+4x+m     Call gate, more privilege, x
                                          parameters
9A  cd    CALL ptr16:16    ts             Call to task


9A  cp    CALL ptr16:32    17+m,pm=34+m   Call intersegment, to full
                                          pointer given
9A  cp    CALL ptr16:32    pm=52+m        Call gate, same privilege
9A  cp    CALL ptr16:32    pm=86+m        Call gate, more privilege, no
                                          parameters
9A  cp    CALL ptr32:32    pm=94+4x+m     Call gate, more privilege, x
                                          parameters
9A  cp    CALL ptr16:32    ts             Call to task


https://en.wikipedia.org/wiki/Far_pointer

https://board.flatassembler.net/topic.php?t=11055


call far ptr https://stackoverflow.com/questions/32706833/how-to-code-a-far-absolute-jmp-call-instruction-in-masm

QuoteThere's one way you can do it, but you need to use MASM's /omf switch so that it generates object files in the OMF format. This means the object files need to be linked with an OMF compatible linker, like Microsoft's old segmented linker (and not their current 32-bit linker.)

To do it you need to use a rarely used and not well understood feature of MASM, the SEGMENT directive's AT address attribute. The AT attribute tells linker that the segment lives at a fixed paragraph address in memory, as given by address. It also tells the linker to discard the segment, meaning the contents of the segment aren't used, just its labels. This is also why the /omf switch has to be used. MASM's default object file format, PECOFF, doesn't support this.

The AT attribute gives the you segment part of the address we want to jump to. To get the offset part all you need to do is use the LABEL directive inside the segment. Combined with the ORG directive, this lets you create a label at the specific offset in the specific segment. All you then need to do is use this label in the JMP or CALL instruction.

For example if you want to jump to the BIOS reset routine you can do this:

bios_reset_seg SEGMENT USE16 AT 0ffffh
bios_reset LABEL FAR
bios_reset_seg ENDS

_TEXT SEGMENT USE16 'CODE'
    jmp bios_reset
_TEXT ENDS


QuoteOr if you want to call the second stage part of your boot loader whose entry point is at 0000:7E00:


zero_seg SEGMENT USE16 AT 0
    ORG 7e00h
second_stage LABEL FAR
zero_seg ENDS

_TEXT SEGMENT USE16 'CODE'
    call second_stage
_TEXT ENDS


____________________________________________________________

Article: Q50405
Product(s): Microsoft Macro Assembler
Version(s): 5.0,5.1,5.1a,6.0,6.0a,6.0b
Operating System(s):
Keyword(s):
Last Modified: 06-MAY-2001

-------------------------------------------------------------------------------
The information in this article applies to:

- Microsoft Macro Assembler (MASM), versions 5.0, 5.1, 5.1a, 6.0, 6.0a, 6.0b
-------------------------------------------------------------------------------

SUMMARY
=======

The PTR operator can be used to specify the size of a register indirect operand
for a CALL or JMP instruction. However, the qualifying operators are not NEAR
and FAR, but WORD and DWORD. For example, to make a near jump to label xxx, use

     JMP WORD PTR xxx

MORE INFORMATION
================

The following example demonstrates how to generate an indirect far call and an
indirect far jump in MASM.

Sample Code
-----------

  ; Assemble options needed: none

            .model  large
            .data
  jumptable DD      routine1
            DD      routine2

            .code
  start:    MOV     ax, @data
            MOV     ds, ax
            CALL    DWORD PTR  jumptable
            JMP     DWORD PTR  jumptable+4
            RET

  cseg      SEGMENT word public 'code'
  routine1  PROC
            RET
  routine1  ENDP

  routine2  PROC
            RET
  routine2  ENDP
  cseg      ENDS

            END     start

Additional query words: kbinf 5.10 5.10a 6.00 6.00a 6.00b

======================================================================
Keywords          : 
Technology        : kbMASMsearch kbAudDeveloper kbMASM510 kbMASM600 kbMASM500 kbMASM600a kbMASM510a kbMASM600b
Version           : :5.0,5.1,5.1a,6.0,6.0a,6.0b

=============================================================================


http://bytepointer.com/masm/ml51_readme.htm

;--- 64-bit call and jumps
;--- there are some problems:
;--- - Masm (ML64) doesn't encode the 16-bit far calls/jumps correctly
;--- - Masm (ML64) doesn't accept the 64-bit far calls/jumps correctly


https://github.com/JWasm/JWasm-regressions/blob/master/CALL64.ASM

aw27

These "instructions" without mnemonic and triggered by macros are used to access call gates and to enter/reenter from protected mode/virtual 86
They are valid, although impossible to use these days except from a boot loader. But Windows will have to use some of them at some point along the boot process which starts in real mode.  With UEFI things are a little different, though.

A few of them:


CALL_FAR3232 MACRO sel, _offset, rpl

        db 9ah
        dd offset _offset
        dw offset sel + rpl

ENDM

JMP_FAR3216 MACRO sel, _offset, rpl

        db 66h
        db 0eah
        dw offset _offset
        dw offset sel + rpl

ENDM

JMP_FAR1632 MACRO sel, _offset, rpl

        db 66h
        db 0eah
        dd offset _offset
        dw offset sel + rpl

ENDM

JMP_FAR3232 MACRO sel, _offset, rpl

        db 0eah
        dd offset _offset
        dw offset sel + rpl

ENDM

JMP_FAR1616 MACRO sel, _offset, rpl

        db 0eah
        dw offset _offset
        dw sel + rpl

ENDM

JMP_FAR_REAL MACRO segmnt, _offset

        db 0eah
        dw offset _offset
        dw segmnt

ENDM



habran

Thanks LiaoMi, this is what produces the source you've provided, however, as you can see no 9Ah

00000008                    *   _DATA ends
00000000                    *   TEST32_TEXT segment
                            *   assume cs:TEST32_TEXT
00000000  B80000                             start : MOV     ax, DGROUP
00000003  8ED8                               MOV     ds, ax
00000005  FF1E0000                           CALL    DWORD PTR  jumptable
00000009  FF2E0400                           JMP     DWORD PTR  jumptable + 4
0000000D  C3                                 RET

00000000                                     cseg      SEGMENT word public 'code'
00000000                                     routine1  PROC
00000000                                     RET
00000000  CB                *   RETf
00000001                                     routine1  ENDP

00000001                                     routine2  PROC
00000001                                     RET
00000001  CB                *   RETf
00000002                                     routine2  ENDP
00000002                                     cseg      ENDS

                                             END     start
0000000E                    *   TEST32_TEXT ends


Thanks AW,
what bothers me is that UASM can not assemble these 2 instructions:
call        0x002A:0x00000018 
call        0x2824:0x0003CBF6
and Difuse can
I'll see how to make it work
Cod-Father

LiaoMi

 :P I successfully created an object file without using mnemonics  :eusa_boohoo: at the end of the disassembled listing ... call    far ptr unk_1002F+7DF1h - "9A"

FARJUMP_TEXT:0000 ; ===========================================================================
FARJUMP_TEXT:0000
FARJUMP_TEXT:0000 ; Segment type: Pure code
FARJUMP_TEXT:0000 FARJUMP_TEXT    segment word public 'CODE' use16
FARJUMP_TEXT:0000                 assume cs:FARJUMP_TEXT
FARJUMP_TEXT:0000                 assume es:nothing, ss:nothing, ds:DGROUP, fs:nothing, gs:nothing
FARJUMP_TEXT:0000
FARJUMP_TEXT:0000 ; =============== S U B R O U T I N E =======================================
FARJUMP_TEXT:0000
FARJUMP_TEXT:0000
FARJUMP_TEXT:0000                 public start
FARJUMP_TEXT:0000 start           proc near
FARJUMP_TEXT:0000                 mov     ax, seg DGROUP
FARJUMP_TEXT:0003                 mov     ds, ax
FARJUMP_TEXT:0005                 call    off_10040
FARJUMP_TEXT:0009                 jmp     off_10044
FARJUMP_TEXT:0009 start           endp
FARJUMP_TEXT:0009
FARJUMP_TEXT:000D ; ---------------------------------------------------------------------------
FARJUMP_TEXT:000D                 retn
FARJUMP_TEXT:000D ; ---------------------------------------------------------------------------
FARJUMP_TEXT:000E                 align 4
FARJUMP_TEXT:000E FARJUMP_TEXT    ends
FARJUMP_TEXT:000E
_DATA:0000 ; ===========================================================================
_DATA:0000
_DATA:0000 ; Segment type: Pure data
_DATA:0000 _DATA           segment word public 'DATA' use16
_DATA:0000                 assume cs:_DATA
_DATA:0000 off_10040       dd routine1             ; DATA XREF: start+5↑r
_DATA:0004 off_10044       dd routine2             ; DATA XREF: start+9↑r
_DATA:0008                 align 10h
_DATA:0008 _DATA           ends
_DATA:0008
CSEG:0000 ; ===========================================================================
CSEG:0000
CSEG:0000 ; Segment type: Pure code
CSEG:0000 CSEG            segment word public 'CODE' use16
CSEG:0000                 assume cs:CSEG
CSEG:0000                 assume es:nothing, ss:nothing, ds:DGROUP, fs:nothing, gs:nothing
CSEG:0000
CSEG:0000 ; =============== S U B R O U T I N E =======================================
CSEG:0000
CSEG:0000
CSEG:0000                 public routine1
CSEG:0000 routine1        proc far                ; DATA XREF: _DATA:off_10040↑o
CSEG:0000                 retf
CSEG:0000 routine1        endp
CSEG:0000
CSEG:0001
CSEG:0001 ; =============== S U B R O U T I N E =======================================
CSEG:0001
CSEG:0001
CSEG:0001                 public routine2
CSEG:0001 routine2        proc far                ; CODE XREF: start+9↑J
CSEG:0001                                         ; DATA XREF: _DATA:off_10044↑o
CSEG:0001                 retf
CSEG:0001 routine2        endp
CSEG:0001
CSEG:0001 ; ---------------------------------------------------------------------------
CSEG:0002                 align 10h
CSEG:0002 CSEG            ends
CSEG:0002
_TEXT:0000 ; ===========================================================================
_TEXT:0000
_TEXT:0000 ; Segment type: Pure code
_TEXT:0000 _TEXT           segment para private 'CODE' use16
_TEXT:0000                 assume cs:_TEXT
_TEXT:0000                 assume es:nothing, ss:nothing, ds:DGROUP, fs:nothing, gs:nothing
_TEXT:0000                 jmp     far ptr byte_10010
_TEXT:0005 ; ---------------------------------------------------------------------------
_TEXT:0005                 call    far ptr unk_1002F+7DF1h
_TEXT:0005 _TEXT           ends
_TEXT:0005
_TEXT:0005
_TEXT:0005                 end start


Parameters for assembly - ml.exe /omf FarJump.asm
ml.exe (VS2019)  ::)

Ml.exe uses this code to assemble long calls
VOID PASCAL CODESIZE
emitgroup (
        SYMBOL FARSYM *pgrp
){
        SYMBOL FARSYM *pseg;

        emitsetrecordtype (0x9A);

        emitsindex (pgrp->symu.grupe.groupIndex);
        pgrp->symu.grupe.groupIndex = groupnum++;

        pseg = pgrp->symu.grupe.segptr;
        while (pseg) {
                if (pseg->symu.segmnt.segIndex){

                        OMFBYTE(((pseg->attr == XTERN)? 0xFE: 0xFF));
                        emitsindex (pseg->symu.segmnt.segIndex);
                }
                pseg = pseg->symu.segmnt.nxtseg;
        }
        flushbuffer ();
}


And the code in windows also uses a direct call without mnemonic ...
cPublic IFSFUNC_Present <FAR>,<ES,DS,DI,DI>
cBegin  IFSFUNC_Present

        cmp  _osmajor,4             ; If DosVer < 4 we can't have ifsfunc
        jb   no_ifsfunc
        ;
        ; On IBM Ascot machines that have the boot from ROM dos 4 we need to
        ; avoid making this call because it will cause the machine to hang.
        ; We can detect the Ascot machines via their unique machine id bytes.
        ;
        call far ptr GetModelBytes  ; Model byte in AH, Sub-model byte in AL
        cmp  ah,0fch                ; Q: Do we have an Ascot model byte ?
        jne  Non_Ascot              ;  N: Do IFSfunc presence check.
        cmp  al,0bh                 ; Q: Do we have an Ascot sub-model byte ?
        jne  Non_Ascot              ;  N: Do IFSfunc presence check.
        stc                         ;  Y: Return IFSFunc present !
        mov  ax,1     ;        thus return TRUE
        jmp  short ifs_check_done


The code needs to be corrected so that it is logical, but I put everything together in haste from what I could find.  :icon_exclaim:

LiaoMi

 :biggrin:

C:\masm64\bin>uasm32 /omf FarJump.asm
UASM v2.47, Nov 17 2018, Masm-compatible assembler.
Portions Copyright (c) 1992-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.

FarJump.asm: 41 lines, 2 passes, 1 ms, 0 warnings, 0 errors

C:\masm64\bin>


"9A" - using uasm ...

TEXT:0000 ; Segment type: Pure code
_TEXT:0000 _TEXT           segment para private 'CODE' use16
_TEXT:0000                 assume cs:_TEXT
_TEXT:0000                 assume es:nothing, ss:nothing, ds:DGROUP, fs:nothing, gs:nothing
_TEXT:0000                 jmp     far ptr byte_10010
_TEXT:0005 ; ---------------------------------------------------------------------------
_TEXT:0005                 call    far ptr unk_1002F+7DF1h
_TEXT:0005 _TEXT           ends

aw27

Quote from: LiaoMi on April 24, 2019, 05:44:39 PM
Ml.exe uses this code to assemble long calls
VOID PASCAL CODESIZE
emitgroup (
        SYMBOL FARSYM *pgrp
){
        SYMBOL FARSYM *pseg;

        emitsetrecordtype (0x9A);

        emitsindex (pgrp->symu.grupe.groupIndex);
        pgrp->symu.grupe.groupIndex = groupnum++;

        pseg = pgrp->symu.grupe.segptr;
        while (pseg) {
                if (pseg->symu.segmnt.segIndex){

                        OMFBYTE(((pseg->attr == XTERN)? 0xFE: 0xFF));
                        emitsindex (pseg->symu.segmnt.segIndex);
                }
                pseg = pseg->symu.segmnt.nxtseg;
        }
        flushbuffer ();
}


Humm, do you have the remaining ML.exe source code so that we could fix all bugs from here?  ;) Just wondering.

habran

LiaoMi can you provide the source?
Cod-Father

LiaoMi

Quote from: habran on April 24, 2019, 06:22:54 PM
LiaoMi can you provide the source?

I attached the original FarJump.zip archive in the post above  :idea:

Quote from: AW on April 24, 2019, 06:07:29 PM
Humm, do you have the remaining ML.exe source code so that we could fix all bugs from here?  ;) Just wondering.

The source code is very old, in this case it's just lucky that the topic is related to the basics  :t

habran

I can not see any 9Ah, am I getting blind 8)
Cod-Father

LiaoMi

Quote from: habran on April 24, 2019, 06:55:02 PM
I can not see any 9Ah, am I getting blind 8)

FarJump2.zip



QuoteAnswer nicked out of "MetaWINDOW FAQ - OMF vs COFF Object File Formats.htm"

Since the dawn of PC civilization up until about the time Microsoft Win32 programming tools came along, almost all PC compilers produced object files using the Intel Object Module Format (OMF) standard. Later, Intel introduced 386 processors and 32-bit protected-mode at which point they also expanded the OMF specification for 32-bits, leading to "OMF-386" which became the standard for most PC protected-mode environments. Around this same time, the original Windows NT development team was also designing code, not only for Intel processors, but also to support processors from other vendors. The Microsoft NT team selected a more portable object module format known as Common Object File Format (COFF) derived from the official object-code format for UNIX System V. COFF object modules later became the defacto standard for all Microsoft Win32 development tools, and gained an advantage in being much closer in format to Portable Executable files - the native executable format for Win32 (a COFF-format linker has much less work to create a 32-bit EXE or DLL from a COFF file than from an OMF format file).

Just as there are OMF- and COFF-format object files (.obj's), there are also OMF and COFF format library files (.lib's). The libraries, fortunately, are basically just a collection of the object files, along with some header information that lets the linker determine which object files to use from the library. To make things difficult however, both OMF and COFF use the same file name extensions, .obj and .lib, to reference the two different types of object and library file formats (because of this you can't just look at the file name extension to tell if the object module or library file is OMF or COFF).

The problem with mixing object files and library files from different compiler vendors is that some vendors support COFF, other vendors use OMF, and a few can handle both. Borland, for example, still uses OMF object files and libraries, while Microsoft's 32-bit compilers produce COFF format files. Watcom C/C++ v11.0 seems to prefer COFF when compiling and linking Windows applications, but generates OMF object files for use with their DOS4GW 32-bit protected-mode DOS-extender. Along with this, Microsoft MASM 6.13 produces OMF files by default, but with the /coff switch can emit COFF object files instead.

When it comes time to link files with different formats, different linkers do differnt things. For example, the Microsoft Visual C/C++ linker is designed for COFF format object files and libraries, but will try to convert OMF object files into COFF files if necessary. This works in some cases, but unfortunately Microsoft LINK does not support all OMF record types, so in many situations the linker may still fail when given OMF format object files. Also while Microsoft LINK attempts some support for OMF object files, it will refuse to process any OMF format libraries. Other linkers, such as Borland's TLINK, are designed for OMF object files and will similarly refuse to work with COFF-format object or library files. Some DOS extender and embedded system vendors, such as Phar Lap, provide their own linkers which support both OMF and COFF, giving you a choice.

The bottom line is that mixing OMF and COFF object and library file types can be a mess (plus the cryptic error messages from the linkers don't help). Unless your linker specifically supports it, you should stick with recommended object and library format for your compiler/linker/platform, and avoid mixing OMF and COFF files.