I'm a nitpicker, so I'll have to slightly correct some of the previous statements :icon_mrgreen:
You can use 32-bit CALLs and RETs in 16-bit code segments and the opposite, using 16-bit CALLs and RETs in 32-bit, is also possible.
Here's a sample of a 16-bit code, calling a procedure with 32-bit call/ret:
.286
.model small
.dosseg
.stack 400h
.386
.code
msg1 db "abc$"
p1:
mov ah,9
mov dx,offset msg1
int 21h
;; retd ;!!!
db 66h
ret
start:
push cs
pop ds
call near32 ptr p1 ;!!!
mov ah,4ch
int 21h
end start
And a 32-bit DPMI sample, using 16-bit call/ret:
;--- DPMICL32.ASM: 32bit DPMI application written in MASM syntax.
;--- assemble: JWasm -mz dpmicl32.asm
LF equ 10
CR equ 13
.386
.model small
.dosseg ;this ensures that stack segment is last
.stack 1024
.data
szWelcome db "welcome in protected-mode",CR,LF,0
.code
start:
mov esi, offset szWelcome
call near16 ptr printstring ;!!!
mov ax, 4C00h ;normal client exit
int 21h
;--- print a string in protected-mode with simple
;--- DOS commands not using pointers.
printstring:
lodsb
and al,al
jz stringdone
mov dl,al
mov ah,2
int 21h
jmp printstring
stringdone:
;; retw ;!!!
db 66h
ret
;--- now comes the 16bit initialization part
_TEXT16 segment use16 word public 'CODE'
start16:
mov ax,ss
mov cx,es
sub ax, cx
mov bx, sp
shr bx, 4
inc bx
add bx, ax
mov ah, 4Ah ;free unused memory
int 21h
mov ax, 1687h ;DPMI host installed?
int 2Fh
and ax, ax
jnz nohost
push es ;save DPMI entry address
push di
and si, si ;requires host client-specific DOS memory?
jz nomemneeded
mov bx, si
mov ah, 48h ;alloc DOS memory
int 21h
jc nomem
mov es, ax
nomemneeded:
mov ax, DGROUP
mov ds, ax
mov bp, sp
mov ax, 0001 ;start a 32-bit client
call far ptr [bp] ;initial switch to protected-mode
jc initfailed
;--- now in protected-mode
;--- create a 32bit code selector and jump to 32bit code
mov cx,1
mov ax,0
int 31h
mov bx,ax
mov cx,_TEXT
mov dx,cx
shl dx,4
shr cx,12
mov ax,7
int 31h ;set base address
mov dx,-1
mov cx,0
mov ax,8
int 31h ;set descriptor limit to 64 kB
mov cx,cs
lar cx,cx
shr cx,8
or ch,40h
mov ax,9
int 31h ;set code descriptors attributes to 32bit
push ebx
push offset start
retd ;jump to 32-bit code
nohost:
mov dx, offset dErr1
jmp error
nomem:
mov dx, offset dErr2
jmp error
initfailed:
mov dx, offset dErr3
error:
push cs
pop ds
mov ah, 9
int 21h
mov ax, 4C00h
int 21h
dErr1 db "no DPMI host installed",CR,LF,'$'
dErr2 db "not enough DOS memory for initialisation",CR,LF,'$'
dErr3 db "DPMI initialisation failed",CR,LF,'$'
_TEXT16 ends
end start16
See the near16 and near32 overrides for the call instructions; also retw and retd are used here, to avoid using the ugly DB directive to add size prefixes. This syntax is supported by masm and jwasm.
But the limitations for 16-bit are still true, of course: the value of EIP must remain < 0x10000.
EDIT: RETW/RETD apparently always create a FAR return, so you'll have to use DB instead.