I've been struggling with understanding segmentation for some time now. Here's what I know.

There are different types of segments, such as the code segment, data segment, stack segment, and extra segments. In old architectures (286 and below), segments were limited to 64kB and used a segment:offset addressing scheme. In later architectures, the addressing scheme was changed to a selector:offset scheme where the selector would access an entry in a GDT or LDT which would contain the address of the segment and other information.

Here's what I'm confused about. What's the point of having different types of segments? If they can overlap, than there's no point in having separate data and code segments, just one general type of segment both can go in.

Secondly, if the segments specified in the LDT are for specific processes, what are the segments specified in the GDT for?

How are the segment addresses set in the LDT? I've written assembly code before but I've never had to tell the LDT where to find my segments before. Does the kernel handle all of that?

GDT is for globals. LDT is for locals, and different LDT's are loaded for different process threads.

Here's a link that shows details of how the descriptors are formatted and used. http://www.acm.uiuc.edu/sigops/roll_your_own/i386/regs.html
Scroll down about half way to find what you're looking for.
Hope this helps!

I read it but I still don't understand how they're used...

The different kinds of segments are used in different, specifically optimized ways for different instructions. You can go to the Intel manual for those details (link here:http://www.intel.com/Assets/PDF/manual/253665.pdf). However, I get the feeling that you are less after the nitty-gritty and more interested in the philosophy of why things were designed the way they were.

Here's a brief write-up that covers some of those basics:

Or, if you prefer a bit more detail: http://www.osdever.net/bkerndev/Docs/gdt.htm

Not sure if this is what you're looking for, but good luck.