13

I need to modify some dll, but i don't know, what excatly does segment registers (DS, SS, ...) in protected mode. I learned in school about real 16-bit mode, where segment registers multiply by 16 plus offset in normal register gives effective address in physical memory. In protected mode, there is some flat memory model and virtual memory, where each process "has" 4GB memory, so if registers have 32-bit, then i can address each byte of virtual memory only by "offset" register. So which puproses have segment registers in protected mode, for example

mov eax, dword ptr ds:[20037DA0] 
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Krab
  • 6,526
  • 6
  • 41
  • 78
  • Which disassembler are you using? Perhaps it defaults to always deducing and showing the segment register based on the opcode even if memory isn't segmented. – Michael Mar 11 '13 at 09:37
  • @Michael: i am using ollydbg – Krab Mar 11 '13 at 09:40
  • 1
    The memory still is segmented, even though the most popular OSs only use one segment and set all segment registers to the same value. – Bo Persson Mar 11 '13 at 10:20
  • Is it a Win32 DLL or a Win16 dll? The Win32 ones employ flat memory, and all but ignore the segment registers. The register name `eax` kinda suggests Win32. – Seva Alekseyev Mar 11 '13 at 14:27
  • 2
    This question appears to be off-topic because it is not a practical programming problem. It looks like a theoretical conceptual question better suited to cs.stackexchange.com. – Raymond Chen Nov 11 '13 at 06:21
  • I don't know about 32-bit, but in x86_64 protected mode, there is no segmentation and DS, ES, FS and GS must always be zero. You get a segmentation fault if you try to load any non-zero value into those. (I think 32-bit protected mode may have either flat *or* segmented memory model, but I'm not sure.) – Kerrek SB Nov 11 '13 at 09:08

3 Answers3

10

Some historical background

The 8086 always used a fixed 64KiB Window per segment whose starting address was calculated by (segment register * 16). Since the 80286 there are some special tables in memory (GDT and LDT). These tables contain the starting address, the length and the access rights of a segment. The segment registers (CS, DS, ES, SS - and since 80386: FS, GS) contain indexes into these tables.

So theoretically an operating system may set the offset and the length of a segment in a way it wants to do that: On 8086 DS=0x0123 means: Segment is 64KiB starting from address 0x01230. In 32-bit mode DS=0x0123 may mean: Segment start at address 0xABCD, length is 0xEF bytes - this depends on the content of the GDT and LDT tables created by the operating system. Trying to access a segment outside this range (DS:0x1000 if the length is < 0x1000) will cause an exception (interrupt).

Current situation

However most modern 32-bit operating systems do not really use segment registers any more. Their values are set depending on the mode (kernel or user) because of access rights issues. The starting address is typically 0 and the length is 4GiB.

The real memory protection is done using the MMU so that some areas of memory cannot be accessed in user mode. In modern operating systems the MMU is absolutely essiential. It maps an "absolute" virtual address to a real physical address checking for access right violations.

There is one exception: Some operating systems (Windows and Linux for example) use the FS and/or GS segments to really point to a different memory area.

For this reason in 64-bit mode the x86 processors use the CS register only for access rights issues and FS and GS can be used to add an offset to each address. As far as I know DS, ES and SS are not used while the content of the registers FS and GS does not matter but there are special registers that explicitly give the offset to be added to an operation that uses FS or GS.

Martin Rosenau
  • 17,897
  • 3
  • 19
  • 38
  • FS is used for exception handling on Windows. The stackframe is saved there, so the exception handler can find it's way back. – Devolus Nov 11 '13 at 14:39
  • 1
    @Devolus It's not just exception handling. More generally, `FS` points to the [**TIB**](http://en.wikipedia.org/wiki/Win32_Thread_Information_Block). – Jonathon Reinhart Nov 12 '13 at 04:50
  • 1
    In 64 bit mode cs,ds,es and ss don't exist anymore. Only fs and gs do. – Nubok Jun 08 '17 at 13:42
  • 1
    @Nubok In 64 bit mode CS, and SS still exist (I'm not sure about DS and ES) but their only purpose is to manage the access rights: The CPL of CS for example is used to check if the CPU is running in Ring 0 or in Ring 3 mode. – Martin Rosenau Jun 10 '17 at 08:48
9

Basicaly the purpose is the same as in real mode except the way they work is slightly different. DS in your example selects one memory descriptor in your GDT(google this term if you really wanna understand this, "Global descriptor table") which contains information like base address, end address, granularity etc. Your offset is then added to the base address, the end. If you are on windows (i bet on linux its the same) you dont generaly have to worry about these segment registers, as you said its flat model, that means there should be only one descriptor for all the memory, so if you dont change these registers it should work as if they werent even existing.

Pyjong
  • 3,095
  • 4
  • 32
  • 50
  • There are some important differences in the usage of segment registers between real mode and protected model that need to be taken into account. For example, in protected mode using `ss:` segment override may produce segmentation fault, so it's not possible to use any other register except `esp` and `ebp` as a base register in stack addressing. In real mode you can address stack with whatever registers you want, by using `ss:` segment override. – nrz Mar 11 '13 at 10:44
  • 1
    Hmm, valid point, but for the purpose of reading/writing stack I believe you could just use ds:offset as well while having that whatever register you want as offset. Provided offset points to stack of course. – Pyjong Mar 11 '13 at 10:56
  • 3
    @nrz While `ds/es.base` can definitely differ from `ss.base` (the most basic reason why you wouldn't be able to use these segments interchangeably), that would be a pretty rare setup in 32-bit protected mode and would likely require extra instructions to pass around addresses of local variables in C/C++ (you'd need to account for the segment base difference, so the locals can be accessed via `ds` in the called functions, just like globals). – Alexey Frunze Mar 11 '13 at 23:10
  • @AlexeyFrunze Thanks for the info on on 32-bit protected mode, that's useful to know. – nrz Mar 12 '13 at 00:39
1

I'll give you a simple answer, but for further information I recommend the link below to AMD's architecture documents, very easy reading. PS: I haven't covered Xeon or PAE here..

IA-32 (x86) architecture has a 32bit physical address bus for RAM.

The 32bit bus is further split into 2x 16bits segments each one capable of accessing 2GB of RAM a total of 4GB.
This is called memory bank switching.

In order to allow protection Intel along with MS decided to use one segment for kernelmode and the other for usermode - which is why Windows historically had a 2GB usermode address space. It's an x86 hardware limitation, not a Windows limitation.

The segment registers separated kernel space and userspace addresses. That's how memory protection was implemented.

Furthermore IA-32 general had 32bit internal registers as well, so it couldn't page. This is real mode (no address translation).

Paging requires 36bits I think (don't quote me ) that's where IA32e came in. The extra bits on IA-32e allowed paging from the HDD, this is the only way it could run on x64 Windows since x64 requires NX and it's located at bit 63.

Please read the AMD architecture documents, personally I find them more informative than the Intel versions.

http://developer.amd.com/wordpress/media/2012/10/24593_APM_v21.pdf

PS with AMD64 flat memory was introduced, doing away with segments.

However 32bit processes still need segment registers. On AMD64 when a 32bit process hits top of stack a pointer is thrown to a base address on a new segment register. This way 32bit apps can effectively eat as much RAM as they want, no limit. Well within reason ofc...:)

Hope this helps.