The Wikipedia page on X86 Memory Segmentation says

In real mode, the registers CS, DS, SS, and ES point to the currently used program code segment (CS), the current data segment (DS), the current stack segment (SS), and one extra segment determined by the programmer (ES). The Intel 80386, introduced in 1985, adds two additional segment registers, FS and GS, with no specific uses defined by the hardware.

Was there any technical or social reason to chose FS/GS/ES? Was there a convention with regard to any of these?

  • 3
    ES has some specific uses defined by hardware, with the MOVS instruction for example. FS/GS were almost never used in 16-bit code, even by code that required other '386 features. They were (and are) used in 32-bit code for certain fixed purposes by DOS extenders and operating systems. (eg. FS as a thread local pointer in Windows and Linux). – Ross Ridge Jun 2 '18 at 17:29
  • You could, maybe, see these registers as a bit exotic, which was basically caused by the operating systems of the time: "Standard" DOS applications couldn't use them, as they would have lost compatibility with earlier CPUs, and new, 386-only systems tended to use linear 32bit addressing, thus not having a lot of use for segment registers, so they were pretty much ignored by standard applications and compilers for a long time. – tofro Jun 2 '18 at 21:42

TL;DR: No.

By default all memory addresses are within DS. Exceptions are the destination addresses of STOSx/MOVSx and CMPSx where ES is used (*1). DS can be replaced by any other segment register in all instructions (and ES in STOSx) by adding a segment override prefix.

So with the exception of ES when it comes to string destination segment any Segment can be used at cost of an additional instruction byte. Which segment register to be used when leaving the default is rather arbitary.

The introduction of FS/GS eased the need to reload segment registers.

Adding one segment (FS) eased A=B+C type operations where each of the components resides in a seperate segment, like when doing large amounts of data (tables), without constant reloading of segment registers. After all, each load needs not only to load all segment information, but also runs neccessary priveledge checks.

Adding a two (FS&GS) even removed that restriction, allowing a program to hold three arbitary data segments in addition to Code, Programm Data and Stack.

Fire at Will

*1 - And then there are all addressing modes with BP and SP,as they are calculated with SS as base value - after all, BP is the stack frame pointer.

  • 2
    IMHO, the original 8086 segmentation design was brilliant, save for the lack of a few instructions like mov segreg,immed and second "scratchpad" segment register. The 80286 is my least favorite design, because it massively increased the cost of repeated segment-register loads without doing anything to alleviate the need for them. The wimpy 16-bit selectors make 80386 segmentation just about useless, but fortunately the large offsets minimize the need for it. – supercat Jun 4 '18 at 14:57
  • The 286 competes the 16 bit design as it now offers large and virtual memory while being fully compatible. Any clean 8086 code (that is none using atrocities like huge memory model / calculated segment values) culd run right away in a virtual memory environment. Sure, the implementation how segment descriptors are haldled was less than great. Still, increased speeds did more than compensate for this. Ofc, code written against the segmentation philosopy did not realy do well. Not Intels fault. – Raffzahn Jun 4 '18 at 16:33
  • The 286 design has two major flaws: (1) Loading segment registers is far more expensive than on the 8086. On the 8086, a loop to compute a[i]=b[i]+c[i] with the three values in different segments could cache two of the segments in BX and DX, minimizing the time to reload them, but on the 80286, each mov ds,bx would require reloading a segment descriptor. (2) Segments are too expensive to grant one to each allocation, but it's difficult to consolidate free space that is shared between segments; such inability to do so can make it hard to avoid excessive memory fragmentation. – supercat Jun 4 '18 at 17:14
  • If segments were cheap enough that an object-based language could simply use segment descriptors as object IDs (treat every object as starting at offset zero of some segment), that could have facilitated a really nice design, especially if there were a means of having multiple selector values share a descriptor (e.g. use the upper bits of the selector to choose a descriptor, and the lower bits as a sub-index which would be scaled and added to the offset). Unfortunately, segment selectors are too short to make that useful. – supercat Jun 4 '18 at 17:28
  • 1
    The only way to avoid frequent segment register loads is to arrange related objects into common segments. That can improve things a lot if one is using machine code, but high-level languages don't support that except for one main data segment, the stack segment, and for Turbo Pascal versions before 4.0, the code segment. I know Intel CPUs are what they are, but it's ironic that Intel added FS: and GS: to an architecture where they were no longer really needed. – supercat Jun 4 '18 at 17:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.