What are the advantages of using segment registers in the 8086 microprocessor?

Segmented addressing probably originated with Burroughs.but I could be wrong.

Suppose you have a flat memory model, and a program starting at location 4000. Here I'll write some pseudocode assembly.

4000 load A with 20h
4002 jump to subroutine at 4006h
4005 return from subroutine
4006 load X with 512
4009 store A at location X
400A increment X
400B compare X to 1024
400E branch if not equal to 4009h
4010 return from subroutine

Now this code mentions an absolute address: 4006h, then address of the subroutine. (The other address is part of a branch, and probably stored as a relative offset.) Suppose we store this code on disk, and then later we read it in. If we read it in starting at location 4000h, we are fine. If we read it in elsewhere, we might have a problem.

Now suppose we have a timeshare system, and we want to page programs in and out, and manage memory for the system. We have a problem; we have to correct all the addresses of a program when it is read in. And we can't do that.

Programs often use "jump tables" to look up an address. How do we detect a jump table and correct the address? Further, suppose I *compute* an address. I might do this by taking a value and shifting it a few places. For example, I might have a lookup table for the sine of angles. The sine of angle X is stored as a four-byte floating-point value, starting at location 2000h. I compute the sine by reading the four bytes starting at 2000h + X<<2.

ASL EAX
ASL EAX
ADD EAX, 2000h

Now how do I correct this? There's no way to know that 2000h is a memory address, and not just some value that needs to be added to EAX for some other purpose.

Now suppose I have segmented addressing. I can now write my programs as if they started at location zero. I write all my programs that way, and the loader sets my segment correctly when the program is loaded. Now I don't have to worry about correcting addresses. I can load the program almost anywhere I want in memory, and adjust the segment registers accordingly. I can also have a segment for data and the stack, so that I can lay the program out in memory however I want.

Suppose I need 16K for the program, 8K for the stack, and 8K for data. If I don't have 32K of contiguous memory I can't load the program. However thanks to segmented addressing I can load the parts of the program into different areas.

Now, segmented addressing is falling out of favor. This is because people typically use assemblers and compilers that produce symbolic object code ready for a loader to resolve all symbols when the program is loaded. This is a more complicated process. Early segmented memory allowed loaders to be simpler, and made memory management possible.

Further, when you have a device such as a disk mapped to memory, you can just point the segment there and directly read and write from offset zero.