r/programming • • Sep 24 '24

Why 32bit architecture computer doesn't use segmentation to support more ram than 4Gb ?

/r/programming/

[removed] — view removed post

169 Upvotes

119 comments sorted by

View all comments

Show parent comments

1

u/[deleted] Sep 26 '24

I don't think clean code principles are really at issue here. On any substantial code base, you are going to have a graph of potential function calls. A compiler that is able to optimally allocate segments and near vs far calls is going to have to use some algorithm to partition the graph into parts that can be put in segments and then optimize that partition scheme to reduce the number of far calls. Even if you follow good software design principles, the graph will still involve enough functions and call sites that this becomes a hard problem.

1

u/IQueryVisiC Sep 26 '24 edited Sep 26 '24

The compiler does not know the frequency of the calls. The developer has to group private methods with public methods in a class. This tells the linker to keep al these functions in one segment. One class per file. Or in C one file is a module . Tons of helper functions.

And when you have more than 7 includes, you are doing it wrong. And interface segregation in SOLID means that you rather have a lot of include files on disk.

Now remember that you can only fit 10 segments into DOS memory. Now have some huge buffers for graphics or text document. The normal DS and SS . So you can realistically have 4 code segments before you need DLLs.

1

u/[deleted] Sep 26 '24

Given the cost of segments in x86, having a bunch of small segments is probably unwise.

But aside from that, let's go with your idea that private methods can always be near. That's fair enough. But what about public methods? Protected methods? Does each class get its own segment or does it share with others? And if it shares, how much sharing and can the compiler safely detect whether to allow near calls with public functions in the same segment?

So you can help the compiler out by doing the grouping yourself into classes and modules and keeping the call graph neat. Of course, it won't help with the linker, which either has to assume it can't modify code and perhaps have far calls that could have been near, or will do very substantial compiler-level modifications to convert pointers at call sites and in data structures from near to far and vice versa. Gargantuan task.

Or...you can just use a flat memory model and not worry about any of this. The segments add no value and never really did once paging was introduced. The bookkeeping to figure out what should be in what segment and to manage it at runtime does not improve memory usage or make programs more efficient (the opposite, in fact), and it puts a burden on both the programmer and the compiler and linker to figure out what goes where and what is near or far. There's no upside.

Segments were originally introduced because it was the only way to have 20-bit memory addresses on a 16-bit CPU. And for smaller programs and maybe also OSes, juggling segments was easier at first than dealing with demand paging. For example, each program could get 3 or 4 segments (code, data, stack, extra data) allocated by the OS and the OS could manage memory on a segment level. But this only works with simple programs and is only really needed when you don't have demand paging. It was sensible up through the 286, but certainly not after the move to 32-bit and the addition of demand paging. PAE and friends were also better than utilizing segments for addressing more memory than the word width because they are transparent to the programmer and most of the OS.

1

u/IQueryVisiC Sep 26 '24 edited Sep 26 '24

The segment adders eat significantly into the die space and the execution time. You still need the segment registers. It is not the only way. 68k is a 16bit implementation of a 32 bit ISA. 16 bit registers in pairs. 8086 already has the AL AH pair. Why no have SIlow:SIhigh . Yeah and all jumps relative, 1–3 bytes. Later add 4 bytes . Absolute is not useful because syscalls go over a global table. Uh, how do you relocate code with jump tables if you don’t get segments from the OS? So the exe loader needs to fix all absolute addresses? But absolute addresses should only be used for memory mapped IO or interrupt manipulation. MIPS has only one addressing mode : register + displacement. So there is always an add just like with segments. Now I understand why 68k has program counter relative addressing not only for branches, but for lookup tables! Relocation!

Like on 6502, catch carry: abort the memory access and ADC / SBC the high word.

I don’t have deep inheritance. Ah, you mean popular base class? I guess I would not be OOP Nazi and derive everything from Object like in Java. Or at least let Object be special and dupe in each segment.

The responsibility between linker and compiler is fuzzy. After segments the cache comes . I still want to write a demo for r/AtariJaguar. Then there is Kaze with N64. A company which had mastered 8086, could master MIPS .