On Mon, 2019-07-01 at 21:52 +0200, Sven Barth via fpc-devel wrote: > Hello together! > > For a project at work I need to run 16-bit x86 code on a bare x86 > hardware (more precisely a 8086 VM). Considering that i8086-embedded > had > been added to FPC nearly exactly 3 years ago I though I'd give it a > try > and cross compiled the units for the tiny memory model. However when > I > tried to compile a test program with -Wtcom (cause I've read that > I'd > need to use exe2bin to convert the resulting binary) I get the > following > output: > > === output begin === > > PS C:\fpc\git> .\compiler\ppcross8086.exe -n -Furtl\units\i8086- > embedded > -viwn -FEtestoutput -Tembedded -CX -XXs -Wmtiny > -Wtcom .\fpctests\tembedtest.pp > Target OS: Embedded > Compiling .\fpctests\tembedtest.pp > Linking testoutput\tembedtest.com > tembedtest.pp(7,1) Warning: Object prt0t.o not found, Linking may > fail ! > tembedtest.pp(7,1) Warning: Object prt0t.o not found, Linking may > fail ! > tembedtest.pp(7,1) Error: Can't open object file: prt0t.o > tembedtest.pp(7,1) Fatal: There were 1 errors compiling module, > stopping > Fatal: Compilation aborted > > === output end === > > Well, prt0t indeed does not exist for embedded (neither source nor > object file) and looking at the code of $fpcdir/rtl/msdos/prt0t.asm > (or > more precisely prt0comn.asm) that one seems to be quite a bit > dependant > on DOS. > > So what's the state of i8086-embedded? All I need is doing some > calculation code and executing some interrupts (thus I hope that I > won't > need to load the resulting program at address 0, thus overwriting > the > interrupt table ;) ). And of course I'll need to know how I'll need > to > setup the VM's state before jumping into the entry code of the > program. ;)
I made i8086-embedded for the purpose of writing things like 16-bit MS- DOS drivers (.sys files), BIOS code, and especially, my planned 16-bit MS-DOS compatible OS kernel, which hasn't really been started yet, but eventually I'm planning to make: https://sourceforge.net/projects/fpcdos/ But it's all future plans and it's not working yet, so actually, i8086- embedded hasn't been used for anything yet and might need a few tweaks to get it working :) Having said that, the startup code is intentionally omitted, because I expected the user to provide that. The reason is that 16-bit code is a little bit tricky and there are things you cannot do with FPC yet, so writing an asm startup code is required. You can probably take the msdos and win16 startup code as a starting point, but they contain too much dos/win16 specific things, that aren't needed. But feel free to gut them and leave only the basics. The only thing you actually need is to provide an entry point (the "..start" label in nasm) and emit a jump to PASCALMAIN. But, depending on your use case, you need to setup a stack as well (i.e. initialize SS and SP). Highly recommended reading: https://www.nasm.us/doc/nasmdoc7.html#section-7.4 Pay special attention to the "segment class" and the "group" directive and make sure you understand how they work. Make sure you use the same segments and groups like the FPC emitted code for the specific memory model. It is these segment names, classes and groups that make each of the memory model to be what it is (in other words, it simply tells the linker which parts of the program must be combined in a single segment, and which parts can span multiple segments). Feel free to use OpenWatcom's "dmpobj" tool to dump FPC's emitted object files, as well as create linker map files (FPC -Xm) to see what's going on. FPC uses only one group "DGROUP" to specify segments/sections that are in the default data segment, pointed to by DS. In the tiny memory model, all segments are in DGROUP. These things change according to the memory model, however, and the startup code needs to reflect that. The MS-DOS startup code already does, so you should be able to reuse its SEGMENT and GROUP declarations. Regarding whether using startup offset 0 would overwrite the interrupt descriptor table - if you use the tiny memory model, this won't necessarily happen, because tiny model code is inherently position independent and thus can be loaded at any segment, and it will work, because it only uses near pointers for everything and everything (code+data+stack+heap) is in the same segment. In fact DOS does exactly that with COM files - it loads them at any segment that is available. They start at offset $100, but that's because puts a special structure, called PSP at offset 0: https://en.wikipedia.org/wiki/Program_Segment_Prefix So, the PSP would overwrite the IDT (the real mode interrupt table), if it wasn't for DOS loading .COM files at segments different than 0. Basically, the tiny memory model is true PIC code, i8086 style :) The only downside is that all code and data is limited to 64kb :) If it wasn't for this minor detail, it would be perfect :) .EXE files can also be loaded at any segment, but they aren't position independent, since they contain relocations. The relocations are applied by the MS-DOS .exe loader. Here's all there is to it in a nutshell (point 9 explains the actual relocation algorithm): http://www.techhelpmanual.com/354-exe_file_header_layout.html It's trivially easy to write a program that takes an .exe file and relocates it and converts it to a flat binary that works at a fixed address. That would probably be very helpful for i8086-embedded use (e.g. for a bootloader that is loaded at a fixed starting segment), but I still haven't found the time to write it :) Overall, i8086 is tricky, but also a lot of fun :) I suggest you take the msdos startup code, leave the segment/class/group declarations, but remove all the DOS-specific code, just leave the jmp to PASCALMAIN. But make sure that the segment registers (e.g. for tiny model DS=CS is required) and the stack pointer (SS:SP) are initialized (in the tiny model SS must be the same as CS and DS), before you jump to PASCALMAIN. If you can't provide the SS=DS=CS conditions, then you probably need to use a different memory model and maybe a tool for relocating and flattening an MZ .exe image, since you can't make .COM files in the other memory models. Make sure you try using the external linker (OpenWatcom's wlink, invoked by FPC -Xe), because you might encounter bugs with the internal linker if you use segment classes and groups that aren't exactly like in DOS. In fact, I don't even know if the internal linker is enabled for i8086-embedded, but it might be. :) In general, the internal linker should also work, but it might need a few minor tweaks and bug fixes for i8086-embedded, and these could give you major headaches to find out, when you're just starting out with 16-bit code and struggling to find out why your code mysteriously crashes. :) Hope this helps to get you started and feel free to ask if you have any further questions. :) Best regards, Nikolay _______________________________________________ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel