Open stsp opened 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!
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.
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?
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?
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!
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!
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.
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!
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.
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.
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
).
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.
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?
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?