flat assembler
Message board for the users of flat assembler.

Index > Main > How to do 16-bit far call?

Author
Thread Post new topic Reply to topic
grangerx



Joined: 30 Sep 2009
Posts: 3
grangerx 14 Jan 2010, 09:10
Hi all,

Sorry if this has been placed in a FAQ somewhere, but I have a question regarding using FASM to write 16-bit DOS programs.

I'm trying to do a far call within my assembly program, to another location within the same assembly program.

Something like the following:

call far cs:label_to_call

I found someone's post to another forum where he had written a macro to hard-code the instruction format:

http://coding.derkeiler.com/Archive/Assembler/comp.lang.asm.x86/2006-04/msg00319.html

and that works, but I'm assuming there's a proper way to do it without having to resort to a macro.

I searched as much as I could and didn't find anything terribly informative. The main FASM documentation has a nice mention of jmp instructions and talks about the call instructions within that, but doesn't give any examples.

Help?

Thanks in advance!
-GrangerX
Post 14 Jan 2010, 09:10
View user's profile Send private message Reply with quote
DOS386



Joined: 08 Dec 2006
Posts: 1905
DOS386 14 Jan 2010, 10:14
grangerx wrote:
Something like the following: call far cs:label_to_call


Far call within same segment ??? Confused You don't need far calls at all if you don't have > 64 KiB of code.

Quote:
Help? Thanks in advance! -GrangerX


What's the problem ? Supply 2 numbers: segment and offset. Alternatively:

Code:
   push cs
   push blah
   push ax ; "seg"
   push dx ; "off"
   retf
   ;----

blah:
    


Quote:
didn't find anything terribly informative.


MULTISEG.ASM ??? Idea
Post 14 Jan 2010, 10:14
View user's profile Send private message Reply with quote
bitshifter



Joined: 04 Dec 2007
Posts: 796
Location: Massachusetts, USA
bitshifter 14 Jan 2010, 20:05
Haha, what the f?
Code:
; A macro which generates a 16-bit far CALL ("push cs, push ip")
;  to the specified label 'nazwa'
;
; Autor / Author: Bogdan 'bogdro' Drozdowski

macro           skacz   nazwa*
{
  local __1_adres

   mov     word [cs:__1_adres], nazwa
      mov     word [cs:__1_adres+2], cs
       push    cs
  db      9ah             ; CALL far
  __1_adres dd 0
}
    

No need to farcall code in the same segment as CS...
A DOS COM file only loads one segment of code anyway...
Unless you knew where the code resides at this would be useless...

EX: Say we are at CS=0x0050 and some code was at CS=0x1000
then we could use DOS386 method or alernatively call 0x1000:myFunc

_________________
Coding a 3D game engine with fasm is like trying to eat an elephant,
you just have to keep focused and take it one 'byte' at a time.
Post 14 Jan 2010, 20:05
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 14 Jan 2010, 20:27
I think that the purpose of that macro was to complicate disassemblers' life. What I don't understand is why "push cs", opcode 9A already does that so the macro is actually doing "push cs, push cs, push ip".
Post 14 Jan 2010, 20:27
View user's profile Send private message Reply with quote
grangerx



Joined: 30 Sep 2009
Posts: 3
grangerx 14 Jan 2010, 21:56
DOS386 wrote:

grangerx wrote:
Something like the following: call far cs:label_to_call

Far call within same segment ??? Confused You don't need far calls at all if you don't have > 64 KiB of code.


Sorry for the initial confusion and lack of detail/context. I probably shouldn't have said "16-bit DOS" but instead "16-bit BIOS", since I'm working with option-rom code that then boots into a DOS environment to test the results of the option-rom.

I realize it's a rather odd-looking call. The reason for it is that what my project is trying to do is glue-together a pair of Intel X86 Option-ROMs into a single binary so that they are both executed at boot. I have 128K of ROM space on the device [Intel NIC], so I'm trying to do this by creating a glue-logic dummy option-rom header that calls the first (tiny 4K, patch) option-rom (which I am writing) and the larger (59K?) option-rom (for which I only have a binary dump, so I can't recompile). Since the roms expect to be far-called, I was hoping I could just do the call far cs:label_to_call since it looks less odd than the push, push, retf method.

My end goal (hopefully) is to create an overclockers' option-rom that allows various chipset-specific tweaks to be applied to motherboards that have BIOSes that lack the options to change the settings. The Intel NICs have nice option-roms for this, but since I occasionally PXE boot, I didn't want to lose the ability to do that, too.

DOS386 wrote:

What's the problem ? Supply 2 numbers: segment and offset. Alternatively:

Code:
   push cs
   push blah
   push ax ; "seg"
   push dx ; "off"
   retf
   ;----

blah:
    


I have used this method after seeing it. I was just trying to verify if I was doing it the hard way or the easy way. Smile
DOS386 wrote:

Quote:
didn't find anything terribly informative.


MULTISEG.ASM ??? Idea


Doh! I just realized, that example is only included with the FASM for DOS; Since I was trying to work at Option-ROM development, I was using FASM for Linux and running my tests in a QEMU VM that boots to a virtual DOS floppy for testing the results, so I didn't even realize the included examples were different. At one point I did try FASM for DOS, but as far as I could tell FASM for Linux produced the same output as FASM for DOS, so I had never even thought to look at the DOS version afterwards. Smile

Thanks very much for your help!
-GrangerX
Post 14 Jan 2010, 21:56
View user's profile Send private message Reply with quote
grangerx



Joined: 30 Sep 2009
Posts: 3
grangerx 14 Jan 2010, 22:03
LocoDelAssembly wrote:
I think that the purpose of that macro was to complicate disassemblers' life. What I don't understand is why "push cs", opcode 9A already does that so the macro is actually doing "push cs, push cs, push ip".


I'm not sure what the author's purpose was, but thanks for the note about the double Push CS. I would have never caught that.

I appreciate the friendly expertise!
-GrangerX

PS. FASM is a pretty awesome assembler. Thanks Tomasz and everyone!
Post 14 Jan 2010, 22:03
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4354
Location: Now
edfed 14 Jan 2010, 22:29
to do a 16 bits far call, there are two solutions.

imediate far pointer
Code:
use16
call 0:function
    

indirect far pointer
Code:
use16
call far[farpointer]
...
farpointer dd 0:function
    


i recommend the second solution because it lets you manage far pointers as datas.
Post 14 Jan 2010, 22:29
View user's profile Send private message Visit poster's website Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 14 Jan 2010, 22:37
Quote:

call far cs:label_to_call since it looks less odd than the push, push, retf method.

The CS is placeholder for the actual destination code segment or it is really referring to CS register? If the later is the case then just do this:
Code:
push cs
call label_to_call
return_point: ; Example label, you don't actually need it.
    
Now, when the callee executes RETF it will jump to return_point appropriately.

If the destination register is not CS and can't be known at compile time neither then you'll have to replace "PUSH CS" with "PUSH something" where "something" is a register or a memory location that holds the appropriate value. Another method is just having a memory pointer so you can do this:
Code:
 ; For the example I'll just make the call equivalent as above
mov word [pointer+2], cs
call far [pointer]
.
.
.
pointer dd 0:label_to_call ; Thanks edfed, I didn't know this was possible.
.
.
.
label_to_call:    


[edit]Changed the way the pointer is defined.[/edit]
Post 14 Jan 2010, 22:37
View user's profile Send private message Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2465
Location: Bucharest, Romania
Borsuc 14 Jan 2010, 23:22
edfed wrote:
i recommend the second solution because it lets you manage far pointers as datas.
but it's bigger.

_________________
Previously known as The_Grey_Beast
Post 14 Jan 2010, 23:22
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4354
Location: Now
edfed 14 Jan 2010, 23:26
but it is not éa& problem on any pc to have 1024 far pointers ( it is only 4096 bytes).
everybody have a place to manage 1024 farpointers for memory management

just look at the 64KB GDT only to define 8192 descriptors.
Post 14 Jan 2010, 23:26
View user's profile Send private message Visit poster's website Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2465
Location: Bucharest, Romania
Borsuc 14 Jan 2010, 23:28
the data isn't what makes it bigger -- that would be put into the immediate constant anyway. what makes it bigger is the address of the data that is referenced in the call. (with immediates there's no address involved).

I'm just saying he doesn't have to use the second if he doesn't intend to do some data indexing, because there's no point in it.

BTW I had no idea you could do 'dd seg:offset' in FASM, thanks.
Post 14 Jan 2010, 23:28
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4354
Location: Now
edfed 14 Jan 2010, 23:38
Code:
use32
df seg:off
    

this is for Pmode
Post 14 Jan 2010, 23:38
View user's profile Send private message Visit poster's website 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-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.