Discussion:
Referring to a segment
(too old to reply)
Lars Erdmann
2020-08-17 17:11:28 UTC
Permalink
Hallo,

I have a question that might be os specific or maybe also linker/loader
specific to a certain extent but I don't know of any better place to ask:

I am developing for OS/2 which, for the most part, is a 32-bit protected
mode OS.
However, due to its heritage, device drivers are still 16-bit (even
though protected mode) and still consist of multiple code and data segments.
Each segment is reflected by a descriptor table entry (as always in
protected mode) and, this might be OS specific, is assigned a dedicated
GDT selector.
It is possible to build drivers that not only contain 16-bit segments
but also 32-bit segments. Still, these additional 32-bit segments get
assigned a GDT selector and the descriptor entry only encompasses the
start address and size of the combined 32-bit code of that 32-bit segment.

Finally, there exists a FLAT GDT code selector and the descriptor it
points to defines the whole 4 GB of memory address space as the segment
(start address 0, limit = 4GB-1).



Here is the question:
In a device driver, from 16-bit code, I need to get to the selector of a
32-bit segment of the same driver.
I was using IBM's alp.exe assembler and this worked in the following way:

one module, defining all segments (to make them known to linker):
KEECode segment dword public uses16 'CODE'
KEECode ends
... other segments ...
CODE32 segment public dword use32 'CODE'
CODE32 ends


another module:
CODE32 segment public dword use32 'CODE'
CODE32 ends

KEECode segment dword public uses16 'CODE'
...
mov ax,CODE32 ; loads the GDT sel. for the 32-bit code segment into ax
...
KEECode ends


On loading the driver, this was resolved by the loader to load the
static GDT selector of the 32-bit code segment ("CODE32") into ax.


Now, I am forced to move to the Watcom WASM.EXE assembler.
I did the very same as above, but this time, instead of loading the GDT
selector for the 32-bit code segment, it is always the FLAT selector
that is loaded into ax once the driver is loaded in memory.

What is the proper way to reference this 32-bit code segment so that the
proper GDT selector (and not the FLAT selector) is loaded into ax ?
Is this an assembler issue, a linker issue or even both ?


Lars
r***@nospicedham.gmail.com
2020-08-18 00:55:27 UTC
Permalink
Post by Lars Erdmann
Hallo,
I have a question that might be os specific or maybe also linker/loader
I am developing for OS/2 which, for the most part, is a 32-bit protected
mode OS.
However, due to its heritage, device drivers are still 16-bit (even
though protected mode) and still consist of multiple code and data segments.
Each segment is reflected by a descriptor table entry (as always in
protected mode) and, this might be OS specific, is assigned a dedicated
GDT selector.
It is possible to build drivers that not only contain 16-bit segments
but also 32-bit segments. Still, these additional 32-bit segments get
assigned a GDT selector and the descriptor entry only encompasses the
start address and size of the combined 32-bit code of that 32-bit segment.
Finally, there exists a FLAT GDT code selector and the descriptor it
points to defines the whole 4 GB of memory address space as the segment
(start address 0, limit = 4GB-1).
In a device driver, from 16-bit code, I need to get to the selector of a
32-bit segment of the same driver.
KEECode segment dword public uses16 'CODE'
KEECode ends
... other segments ...
CODE32 segment public dword use32 'CODE'
CODE32 ends
CODE32 segment public dword use32 'CODE'
CODE32 ends
KEECode segment dword public uses16 'CODE'
...
mov ax,CODE32 ; loads the GDT sel. for the 32-bit code segment into ax
...
KEECode ends
On loading the driver, this was resolved by the loader to load the
static GDT selector of the 32-bit code segment ("CODE32") into ax.
Now, I am forced to move to the Watcom WASM.EXE assembler.
I did the very same as above, but this time, instead of loading the GDT
selector for the 32-bit code segment, it is always the FLAT selector
that is loaded into ax once the driver is loaded in memory.
What is the proper way to reference this 32-bit code segment so that the
proper GDT selector (and not the FLAT selector) is loaded into ax ?
Is this an assembler issue, a linker issue or even both ?
Lars
Hi Lars!

Here's a reference to an installible file system driver that demonstrates
how to work with 16-bit and 32-bit facets:

Search Hobbes for "driver source code" and you'll find others.
https://hobbes.nmsu.edu/

https://hobbes.nmsu.edu/?detail=%2Fpub%2Fos2%2Fdev%2Fdrivers%2FWatcom_IFS_2005-08-28.zip

Also, check out https://www.os2world.com and ask some of the developers
there. They still have a very active OS/2 community.
--
Rick C. Hodgin
wolfgang kern
2020-08-18 02:19:34 UTC
Permalink
Post by Lars Erdmann
Hallo,
Hi,
[...]
Post by Lars Erdmann
What is the proper way to reference this 32-bit code segment so that the
proper GDT selector (and not the FLAT selector) is loaded into ax ?
Is this an assembler issue, a linker issue or even both ?
I always avoided detours with improper tools. Could well be that what
you miss doesn't exist. 16 bit equivalent to 32 bit Flat code cannot be
except if the 16 bit code seg starts at 0:0 which is a pretty bad idea.

If you need two entries which point to the same memory in the GDT then
just create them or copy one existing and modify it as desired.
I use two such 16/32 pairs for both code and data [in the HMA range so
this memory is accessible by trueRM16 too].
__
wolfgang
Lars Erdmann
2020-08-20 22:08:19 UTC
Permalink
Post by wolfgang kern
Post by Lars Erdmann
Hallo,
Hi,
[...]
Post by Lars Erdmann
What is the proper way to reference this 32-bit code segment so that
the proper GDT selector (and not the FLAT selector) is loaded into ax ?
Is this an assembler issue, a linker issue or even both ?
I always avoided detours with improper tools. Could well be that what
you miss doesn't exist. 16 bit equivalent to 32 bit Flat code cannot be
except if the 16 bit code seg starts at 0:0 which is a pretty bad idea.
You misunderstood.
It is a 32-bit segment (the segment defined by using the USE32
directive) that is loaded somewhere in virtual address space, with a
linear start address <> 0 and the length of all the combined 32-bit
code. It is NOT a flat segment even though it is a 32-bit segment.
And this segment is addressed by a GDT selector (and the descriptor that
is points to) that happens to have that linear start address and segment
limit. This GDT descriptor is created by the OS loader when the driver
is loaded.
The one thing that annoys me is that one assembler creates an object
file that will contain a fixup that will eventually be replaced by the
proper GDT selector (created by the OS loader) whereas the other
assembler creates a fixup that will eventually be replaced by the FLAT
selector.
I know too little about the OMF format to understand what these 2
assemblers do differently so that the loader will fail in properly
fixing up this selector value.
Post by wolfgang kern
If you need two entries which point to the same memory in the GDT then
just create them or copy one existing and modify it as desired.
I use two such 16/32 pairs for both code and data [in the HMA range so
this memory is accessible by trueRM16 too].
Yes, it would be possible to dynamically allocate my own GDT descriptor
and have that set with the proper linear base address and limit (there
are OS kernel functions to do that) but that would create an unnecessary
GDT entry that already exists (and GDT entries are a scarce resource for
a segmented OS that OS/2 still is).

Lars

Loading...