I am doing some work on 8086 real mode. I am used to doing it in assembly, but wanted to give C compilers a try. It seems to me that compilers assume that all the segment registers have the same value. It is not so in my case; SS is 0x4C0, while the DS = ES = CS = 0x800.
So the following when compiled, produces code without taking into the fact that SS <> DS.
[Source: here]
uint8 ch;
void main()
{
uint8 hexchars[] = {'0','1','2','3','4','5','6','7','8','9','A','B',
'C','D','E','F'};
uint8 i = 0;
ch = hexchars[i];
}
When compiled, the assignment produces: [Full source: here]
// ch = hexchars[i];
00000156 8A46FF mov al,[bp-0x1] ; 'i' is at [BP - 0x1]
00000159 30E4 xor ah,ah
0000015B 89C7 mov di,ax
0000015D 89EE mov si,bp
0000015F 89FB mov bx,di
00000161 8A40EF mov al,[bx+si-0x11 ; 'hexchars[0] is at [BP - 0x11]
00000164 A28401 mov [0x184],al ; 'ch' is at location 0x184
Because SS is not explicitly mentioned, DS will be assumed by the assembler.
As stated above in my case SS <> DS, thus AL now has a value from a wrong address.
MOV AL, DS:[BX + SI - 0x11] <> MOV AL, SS:[BX + SI - 0x11]
Compilers I have tried:
1. GCC Version 6.2.0 (Sourcery CodeBench Lite 2016.11-64)
ia16-elf-gcc -Wall main.c -o main.com -T main.ld
Linker file is as follows:
OUTPUT_FORMAT(binary)
SECTIONS
{
. = 0x0;
.text :
{
*(.text);
}
.data :
{
*(.data);
*(.bss);
*(.rodata);
}
_heap = ALIGN(4);
/DISCARD/ :
{
*(.eh_frame)
}
}
2. Bruce's C compiler [Full source used with BCC here]
bcc -ansi -0 -W -c main.c -o main.o
ld86 -d main.o -o main.com -T000
UPDATE: Tried SmallerC. Here again compiler is assuming SS = DS.
3. Smaller C [Source here]
smlrc -seg16 -Wall main.c main.s
nasm -f bin main.s -o main.com
The result is more or less the same in both the compilers. No compiler is explicitly specifying SS when reading from stack. The question is there a way to inform the compiler about the constraint, am I doing something wrong.