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
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.
deleted
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:
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 ;)
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://en.wikipedia.org/wiki/Far_pointer)
https://board.flatassembler.net/topic.php?t=11055 (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 (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 (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 (https://github.com/JWasm/JWasm-regressions/blob/master/CALL64.ASM)
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
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
: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:
: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
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.
LiaoMi can you provide the source?
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
I can not see any 9Ah, am I getting blind 8)
Quote from: habran on April 24, 2019, 06:55:02 PM
I can not see any 9Ah, am I getting blind 8)
FarJump2.zip(https://i.ibb.co/hstSNCS/FarJump2.png)
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.
It would seem to me that the problem is finding a use for such a mnemonic. For assemblers that address a wider range of x86 host platforms, it may be useful but it has long been the case that Intel have stray mnemonics that change from one chip family to another for undisclosed reasons so there may not be any gain in adding the mnemonic to a working assembler.
For test purposes most macro assemblers should be able to code the mnemonic and see if it can be used for anything but in a world that lives between win32 and the coming win64, this may be a task that simply wastes time.
Thanks LiaoMi
I succeeded to assemble it, however linking it is another thing
_main PROC NEAR
push ebp ; 0000 _ 55
mov ebp, esp ; 0001 _ 8B. EC
add esp, -8 ; 0003 _ 83. C4, F8
push -11 ; 0006 _ 6A, F5
call _GetStdHandle@4 ; 0008 _ E8, 00000000(rel)
mov dword ptr [ebp-8H], eax ; 000D _ 89. 45, F8
push 0 ; 0010 _ 6A, 00
lea eax, ptr [ebp-4H] ; 0012 _ 8D. 45, FC
push eax ; 0015 _ 50
push 17 ; 0016 _ 6A, 11
push offset FLAT:?_009 ; 0018 _ 68, 00000000(segrel)
push dword ptr [ebp-8H] ; 001D _ FF. 75, F8
call _WriteConsoleA@20 ; 0020 _ E8, 00000000(rel)
int 3 ; breakpoint or filler ; 0025 _ CC
call far ptr FLAT:?_002 ; 0026 _ 9A, 000002A4 0000(far)
call ?_004 ; 002D _ E8, 3FD65AD9
@hutch,
we are working on new codegen.c and we don't want to make it worse but better ;)
so, we needed testing peace for that instruction, which as we can see no one used for long, long, long time
Thanks all of you
Quote
linking it is another thing
You need the Segmented Executable Linker, it is called link16.exe (or I renamed it to link16.exe ).
deleted
Thanks AW and nidud :t
The only time I ever used these specific opcode forms was when writing OS code, DOS extenders etc. They were necessary to force a cache-flush and load a new CS selector. Even then with tasm/dos I think used to manually code in the db 0eah, dd xxx, dw 8 .. and patch it.