In 16 bits mode (real mode) you cannot have more then 64 KiB in a single segment. Since you are not creating an EXE file, you cannot:
1 - Jump to another "segment" (there's only one);
2 - Declare uninitialized data (resb);
3 - Do a direct far jump or call...
This will compile, but will create the wrong code:
org 0x800
xor ax,ax
mov si,ax
mov ss,ax
mov ax,0x800
mov sp,ax
mov [jmp_addr+2],cs
; JMP NEAR
test_001:
mov si,0x1
jmp test_001a_ok
hlt
jmp_addr:
dw test_003_ok
dw 0
test_001a_ok:
; JMP FAR
test_003:
mov si,0x3
jmp far [jmp_addr]
hlt
hlt
hlt
times 70000 nop
hlt
hlt
hlt
test_003_ok:
nop
mov ax,0xa5ee
mov si,ax
hlt
Because that times 70000 nop will get you an image bigger than 64 KiB, so test_003_ok will be a reference inside your code segment (not outside)... test_003_ok will be offset 0x1_1196. but the offset reference in jmp_addr will be 0x1196, thus, wrong!
You can use 386 instructions in real mode and "normalize" the "physical address" like this:
...
mov eax,test_003_ok ; this will be a 32 bits offset.
mov bx,cs
movzx ebx,bx
shl ebx,4
add eax,ebx ; EAX has the "physical address" of test_003_ok.
mov ebx,eax
and ax,0x0f
shr ebx,4 ; BX:AX is now the logical "normzlized" address of test_003_ok
mov [jmp_addr],ax
mov [jmp_addr+2],bx
jmp far [jmp_addr]
jmp_addr:
dw 0, 0
...
Notice you'll have to calculate seg:offset to access anything beyond the first segment. (and I don't know if this will work with a .COM file no MS-DOS, for example).