What does normalization mean in huge pointers

I have a lot of confusion in understanding the difference between the "far" pointer and the "huge" pointer, which Google was looking for all this to solve, could not find it. Can anyone explain me the difference between the two. In addition, what is the exact concept of normalization associated with huge pointers.

Please give me the following or any similar answers:

"The only difference between the far pointer and the huge pointer is that the compiler normalizes the huge pointer. A normalized pointer is one that has as many addresses in the segment as possible, which means that the offset is never greater than 15. The huge pointer is normalized only then when pointer arithmetic is performed on it. It does not normalize when assigned. You can make it normalize without changing the value, increase or decrease it. less than 16, because a segment can represent any value ix, greater than or equal to 16 (for example, the absolute address 0x17 in normalized form is 0001:0001 . Although far pointer can address the absolute address 0x17 using 0000:0017 , it's not really a huge (normalized) indicator, because the displacement of more than 0000F .) Huge pointers can also be increased and decreased using arithmetic operators, but since they are normalized, they will not wrap around how far the pointers are. "

Here the concept of normalization is not well explained, or maybe I can not understand it very well.

Can someone try to explain this concept from the point of view of beginners.

Thanks, Rahamath

+6
c pointers
source share
3 answers

At the beginning of 8086 there was an extension of the 8-bit processor 8085. The 8085 could only address 65,536 bytes with its 16-bit address bus. When Intel developed the 8086, they wanted the software to be as compatible as possible with older 8-bit processors, so they introduced the concept of segmented memory addressing. This allowed us to run 8-bit software to live in a wider range of addresses without noticing. The 8086 had a 20-bit address bus and could handle up to 1 MB of memory (2 ^ 20). Unfortunately, he could not directly address this memory, for this it was necessary to use segment registers. The real address was calculated by adding the value of the 16-bit segment shifted 4 left, added to the 16-bit offset.

 Example: Segment 0x1234 Offset 0x5678 will give the real address 0x 1234 +0x 5678 --------- =0x 179B8 

As you noticed, this operation is not bijective, that is, you can generate a real address using other combinations of segment and offset.

  0x 1264 0x 1111 +0x 5378 +0x 68A8 --------- --------- etc. =0x 179B8 =0x 179B8 

Actually, 4096 different combinations are possible due to 3 overlapping nibbles ( 3*4 = 12 bits, 2^12 = 4096 ). The normalized combination is the only one in 4096 possible values ​​that will have 3 high nibble offsets to zero. In our example, it will be:

  0x 179B +0x 0008 --------- =0x 179B8 

The difference between the far and huge pointers is not normalized, you can have a huge non-normalized pointer, this is an absolute resolution. The difference lies in the code generated when performing pointer arithmetic. With pointers with a large pointer, adding or adding values ​​to the pointer will not handle overflow, and you will be able to process 64 KB of memory.

 char far *p = (char far *)0x1000FFFF; p++; printf("p=%p\n"); 

prints 1000:0000 For huge pointers, the compiler generates the code needed to handle the transfer.

 char huge *p = (char huge *)0x1000FFFF; p++; printf("p=%p\n"); 

will print 2000:0000

This means that you must be careful when using large or large pointers, since the cost of arithmetic with them is different.

Also, one should not forget that most 16-bit compilers had libraries that did not handle these cases correctly, sometimes providing buggy software. The Microsoft real-time compiler did not handle huge pointers to all of its string functions. Borland was even worse because even mem functions ( memcpy , memset , etc.) did not handle offset overflow. That is why it was a good idea to use normalized pointers with these library functions, the probability of offset overflow was lower with them.

+13
source share

The first thing to understand is converting a segmented pointer to a linear address. For example, you have a conversion:

 linear = segment * 16 + offset; 

Because of this, it turns out that the same linear address can be expressed using different combinations of segments / offsets. For example, the following combinations of segments / offsets refer to the same linear address:

 0004:0000 0003:0010 0002:0020 0001:0030 0000:0040 

The problem is that if you have ptr1 with the segmented address 0100:0000 and ptr2 with the segmented address 0010:0020 , a simple comparison will determine that ptr1 != ptr2 , even if they actually point to the same address.

Normalization is the process by which you convert an address to a form so that if two non-normalized pointers refer to the same linear address, they will both be converted to the same normalized form.

+10
source share

As I recall, this is something like this:

  • Next to the pointers, memory is indicated in the same segment (as a pointer).
  • Far pointers indicate memory in another segment.
  • Huge pointers allow you to point to a memory size exceeding a segment (so you can have a block> 64k and do arithmetic on your pointer and what Samuel said).

If you are new, it is best to forget what you heard about Near / Far / Huge. They only make sense in the old 16-bit segmented memory model, which was often found on earlier Intel 80x86s. In 32- and 64-bit land (that is, everything since 1994), memory is just a large continuous block, so a pointer is just a pointer (for one application).

+1
source share

All Articles