tkchia / gcc-ia16

Fork of Lambertsen & Jenner (& al.)'s IA-16 (Intel 16-bit x86) port of GNU compilers ― added far pointers & more • use https://github.com/tkchia/build-ia16 to build • Ubuntu binaries at https://launchpad.net/%7Etkchia/+archive/ubuntu/build-ia16/ • DJGPP/MS-DOS binaries at https://gitlab.com/tkchia/build-ia16/-/releases • mirror of https://gitlab.com/tkchia/gcc-ia16
GNU General Public License v2.0
179 stars 13 forks source link

i386 support? #125

Open stsp opened 1 year ago

stsp commented 1 year ago

Hello.

Currently in inline asm the 386 regs (like fs, gs) are not recognized. Exx regs are not available, operations like "setc" etc - same. I looked into the manual page and it seems 286 is the currently "best" CPU supported. So I have to do a lot of hard-coding in inline asm, putting hex values as opcodes.

While I realize emitting i386 code by the compiler itself may be a big task, what about at least allowing it on an assembler level?

ghaerr commented 1 year ago

Hello @stsp,

I'm not completely sure of this, but perhaps placing a " .arch i386\n" at the start of your inline asm will work - this is required and works for ASM .s and .S files to tell the assembler that 386 instructions are allowed (I think the default is ".arch i8086").

Thank you!

stsp commented 1 year ago

Thanks! That indeed works. But I'll leave this open for now in case the more convenient way of doing that, can be added in the future. Feel free to close though.

stsp commented 1 year ago

In fact, adding ".arch i386\n" in some inline asm and not adding '.arch i286\n" in the end of that inline asm, results in a serious size difference in resulting binary. It is smaller than before. But using ia16-elf-gcc -S reveals no differences, so something is very strange on an assembler level... Can assembler do some 386-specific optimizations on its own, or what?

stsp commented 1 year ago

ia16-elf-objdump provides a 32bit disassemble, so I can't use it to see the difference. Perhaps ia16-elf-objdump should be fixed to provide 16bit disassembly?

ghaerr commented 1 year ago

Hello @stsp,

Perhaps ia16-elf-objdump should be fixed to provide 16bit disassembly?

Use ia16-elf-objdump -D -r -Mi8086 for 16-bit disassembly.

Thank you!

tkchia commented 1 year ago

Hello @stsp,

But using ia16-elf-gcc -S reveals no differences, so something is very strange on an assembler level... Can assembler do some 386-specific optimizations on its own, or what?

One possibility I can think of is that the assembler is emitting long conditional jumps (opcode 0f 8x ...), which only exist on the 386 and above, or other nasties if .arch i386 is in effect. If you need the parts outside your inline assembly to work even on a 286, you will need to look out for these things.

Thank you!

stsp commented 1 year ago

OK so using @ghaerr 's ia16-elf-objdump -D -r -Mi8086 I was able to verify that the long conditional jumps are exactly the culprit. :) So you both are right. So it seems gcc emits jumps w/o calculating the length, and gas looks for a length and if it is too high, replaces the conditional jump with inverted conditional jump and the unconditional jump.

So I would guess in this case enabling 386 code would be good for optimization. And maybe one day the compiler itself will be able to generate 386 code, which would probably be very good.

tkchia commented 1 year ago

Hello @stsp,

And maybe one day the compiler itself will be able to generate 386 code, which would probably be very good.

There is already mainline i686-linux-gnu-gcc or x86-64-linux-gnu-gcc -m32 (etc.) for that, no? They even use pretty much the same object file (.o) format as ia16-elf-gcc. Though we might need to add some glue code to bridge the differences between 16-bit and 32-bit procedure calling conventions. This all depends on what you really need/want to do at the high level.

Thank you!

stsp commented 1 year ago

But gcc -m32 doesn't generate exe files, either real-mode ones (with far pointers) or dpmi ones. Another difference is that -m32 assumes 32bit code while ia16-gcc needs to generate 16bit code but that doesnt necessary mean 186 code (I can even use data32 prefixes). If I can use normal gcc for that please let me know, but I dont think its the case.

stsp commented 1 year ago

Note that causeway is full of a 32bit assembly (and of course the usage of all 386 regs), so using .286 for -mdosx doesn't look sensible.

asiekierka commented 1 year ago

Another difference is that -m32 assumes 32bit code

You can use gcc -m16, which will generate 32-bit code that runs in 16-bit mode; of course, this would still introduce issues in the linking stage, as you pointed out - while mainline x86 GCC can generate 32-bit code with the appropriate prefixes to run in 16-bit mode on an 80386+ processor, it does not understand segmentation, so medium memory model linking will not work in this manner (tiny/small might - it's unexplored territory). I fail to see a notable enough usecase for this; typically, when targetting 386+ CPUs, people just use DJGPP and a DOS extender... This matters as the effort to add 32-bit code generation support to the IA-16 backend would be rather large.

I would be surprised if it was difficult to add at least some 386+ opcode support to the assembler, but that's an issue for binutils-ia16, not gcc-ia16.

Here's a snippet from GAS documentation which explains the limitations of -m16 at a lower level (.code16gcc mode, as opposed to .code16).

stsp commented 1 year ago

By saying "to generate 386 code" I mainly meant all 386 registers, longer conditional jumps and so on, but not 32bit code, which would then be full of prefixes. So yes, I agree not too much is needed on a compiler level here. Just allow asm to use i386 arch, and that seems sufficient for everything.

Yes, its probably possible to generate some .com file with .code16gcc. But without a proper library support and w/o far pointers you won't go too far.

stsp commented 1 year ago

Hmm, and in fact: ia16-elf-gcc: ошибка: medium model not supported in DOS extender mode So why am I talking about far pointers... So if I could use -m16 mode with ia16-elf-ld to produce a dosx-stubbed executables, and with libi86, then that would be a very interesting experiment. Do you think its possible?