Page 1 of 1

Problem with far pointers (16 bit real mode)

Posted: Wed Jun 29, 2016 9:17 pm
by drunkenfox
I currently have a real mode c "kernel" (it's only in its early stage) that i compile with watcom's toolchain. The kernel gets loaded with cs being 0x800, which matches the linker script's segments and offset definitions. I skimmed through watcom's manual and used the __segment modifier as so:

Code: Select all

__segment screen = 0xb800;
char __based(void)* scrptr = 0;

while (scrptr < 80 * 25) {
      *(screen:>scrptr) = '!';
      scrptr += 2;
}
Dissasembly:

Code: Select all

                 mov     ds:word_911E, 0B800h
seg000:1014                 xor     ax, ax
seg000:1016                 mov     ds:word_911C, ax
seg000:1019                 jmp     short loc_9023
seg000:101B ; ---------------------------------------------------------------------------
seg000:101B
seg000:101B loc_901B:                               ; CODE XREF: sub_9000+35j
seg000:101B                 cmp     ds:word_911C, 7D0h
seg000:1021                 jnb     short loc_9037
seg000:1023
seg000:1023 loc_9023:                               ; CODE XREF: sub_9000+19j
seg000:1023                 mov     bx, ds:word_911C
seg000:1027                 mov     es, ds:word_911E
seg000:102B                 mov     byte ptr es:[bx], 21h ; '!'
seg000:102F                 inc     bx
seg000:1030                 inc     bx
seg000:1031                 mov     ds:word_911C, bx
seg000:1035                 jmp     short loc_901B
-which fills the screen as intended with exclamation marks. However, this code just doesn't do anything and seems to get the IP register lost in memory as any following code doesn't get executed:

Code: Select all

char __far* text = 0xb8000;

while (i < 80 * 25) {
      text[i] = '?';
      i += 2;
}
Disassembly yields the following:

Code: Select all

loc_9037:                               ; CODE XREF: sub_9000+21j
seg000:1037                                         ; sub_9000+53j
seg000:1037                 mov     ax, ds:word_8008    [just a zero in the datasegment]
seg000:103A                 cmp     ax, 7D0h
seg000:103D                 jge     short loc_9055
seg000:103F                 mov     bx, 912h
seg000:1042                 mov     es, bx
seg000:1044                 assume es:nothing
seg000:1044                 mov     bx, es:0
seg000:1049                 add     bx, ax
seg000:104B                 mov     byte ptr [bx], 3Fh ; '?'
seg000:104E                 add     ds:word_8008, 2
seg000:1053                 jmp     short loc_9037
Is there a way to get the far pointer method to work like the segment offset method? I want to be able to use subscripts, especially when I start doing heavy lifting in non-text modes.

Re: Problem with far pointers (16 bit real mode)

Posted: Wed Jun 29, 2016 9:48 pm
by alexfru
This looks strange. AFAIK, far pointers must be initialized using the MK_FP(seg, ofs) macro as the initializer. It should come from <dos.h>.

Re: Problem with far pointers (16 bit real mode)

Posted: Thu Jun 30, 2016 2:09 am
by Combuster
I remember that you have to actually use it that way in Turbo C or it wouldn't work. IIRC it expands to 0xb8000000 rather than 0x000b8000 to match an explicit segment and offset word.

Re: Problem with far pointers (16 bit real mode)

Posted: Sat Jul 02, 2016 7:59 pm
by drunkenfox
alexfru wrote:This looks strange. AFAIK, far pointers must be initialized using the MK_FP(seg, ofs) macro as the initializer. It should come from <dos.h>.
Yes, that worked. Thank you.