I am reading about memory addressing. I read about segment offset and then about descriptor offset. I know how to calculate the exact addresses in real mode. All this is OK,
Minimal example
With:
msgdsmov $0, %ax
mov %ax, %ds
mov %ds:msg, %al
/* %al contains 1 */
mov $1, %ax
mov %ax, %ds
mov %ds:msg, %al
/* %al contains 2: 1 * 16 bytes forward. */
msg:
.byte 1
.fill 15
.byte 2
So if you want to access memory above 64k:
mov $0xF000, %ax
mov %ax, %ds
Note that this allows for addresses larger than 20 bits wide if you use something like:
0x10 * 0xFFFF + 0xFFFF == 0x10FFEF
On earlier processors which had only 20 address wires, it was simply truncated, but later on things got complicated with the A20 line (21st address wire): https://en.wikipedia.org/wiki/A20_line
On a GitHub repo with the required boilerplate to run it.