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
172 stars 12 forks source link

General discussion regarding this platform? #66

Open ladmanj opened 3 years ago

ladmanj commented 3 years ago

Hello

I know, this isn't bug report, i don't want to be annoying. Is there any other way to contact the community involved in ia16 asm and gcc topic?

Thank everyone 😊

mfld-fr commented 3 years ago

Hello @ladmanj

Looks like we are both hacking a non-PC IA16 device 😉

tkchia commented 3 years ago

Hello @ladmanj,

Is there any other way to contact the community involved in ia16 asm and gcc topic?

I am not sure, but perhaps VOGONS might be a good place? It seems to be mostly geared towards IBM PC-compatibles (with MS-DOS or old Windows versions), and old Macs --- but you might have some luck there. I have not yet joined myself, but I may in the future.

Generic, platform-independent issues about GCC can probably use one of the official GCC mailing lists, e.g. gcc-help. Issues specific to gcc-ia16 can come here, for lack of a better place. 😑

There is of course also Stack Overflow, but you probably already know that.


Hello @mfld-fr,

Looks like we are both hacking a non-PC IA16 device :wink:

This to me brings up a question: do you think there is utility in having gcc-ia16 directly support writing programs to be burnt onto EPROMs? To me this seems to be an extremely niche area (even more so than writing PC booter programs), but maybe I am missing something.

Thank you!

tkchia commented 3 years ago

Hello @ladmanj,

By the way, @mfld-fr wrote an emu86 emulator which helps debug x86-16 code meant for EPROMs. You may find it helpful.

Thank you!

mfld-fr commented 3 years ago

@tkchia : I think you are right, hard bare metal on IA6 is only for a very few. GCC-IA16 already does the job, at the cost of a little but must have assembly code for the glue...

ghaerr commented 3 years ago

Hello @tkchia and @mfld-fr,

do you think there is utility in having gcc-ia16 directly support writing programs to be burnt onto EPROMs?

When the ELKS kernel is configured for far text, the gcc-ia16 output is not usable when directly burned in ROM because of the required text relocations. In non-ROM scenarios, this is handled by setup.S when copying from the disk image. A nice addition would be having the ability to specify a final text segment with the linker or elf2elks, which would relocate the .text and .fartext sections and emit a short-form a.out header. Without it, a separate utility will have to be written to allow the ELKS fartext kernel to be ROMable. This could be somewhat easily tested by setting the final text segment to be REL_SYS, in which case the normal ELKS boot/setup.S should load it successfully without modification. I am much less concerned with data segment relocations, as haven't been any so far, and likely could be worked around if generated.

With @mfld-fr's EMU86 now able to show that the current ELKS kernel will run in ROM, this would be nice to have.

Thank you!

ladmanj commented 3 years ago

Hello @tkchia,

By the way, @mfld-fr wrote an emu86 emulator which helps debug x86-16 code meant for EPROMs. You may find it helpful.

I will definitely try it

Hello @mfld-fr

Looks like we are both hacking a non-PC IA16 device wink

Welcome my brother :-)

ladmanj commented 3 years ago

Hello all

I'm trying to use the technique from here https://sourceware.org/binutils/docs/ld/Output-Section-LMA.html#Output-Section-LMA

But I'm getting these errors:

(.text._init_mem+0x5): undefined reference to `_data!'
(.text._init_mem+0x8): undefined reference to `_etext!'
(.text._init_mem+0xc): undefined reference to `_data!'
(.text._init_mem+0xf): undefined reference to `_edata!'
(.text._init_mem+0x14): undefined reference to `_bstart!

I don't understand why the linker doesn't behave as the documentation is describing. Probably different versions of gnu linkers differ in behaviour.

Thanks

ladmanj commented 3 years ago

OMG, there is the same example with different syntax - i will try it immediately, but I feel I should warn you. https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_chapter/ld_3.html

Thanks

ladmanj commented 3 years ago

OMG, there is the same example with different syntax - i will try it immediately, but I feel I should warn you. https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_chapter/ld_3.html

Thanks

But the result doesn't differ :-(

tkchia commented 3 years ago

Hello @ghaerr,

A nice addition would be having the ability to specify a final text segment with the linker or elf2elks, which would relocate the .text and .fartext sections and emit a short-form a.out header. Without it, a separate utility will have to be written to allow the ELKS fartext kernel to be ROMable.

Let me look into that. Thanks!

ladmanj commented 3 years ago

Hello @tkchia

Let me look into that. Thanks!

Please also kindly look at the linker code. I'm afraid, that there may be a bug.

For example, the function SIZEOF(.text) in the linkerscript returns wrong value. There is 0x85, and the actual .text code size is around 0xcb0 (not exactly, I'm not looking at it right now, but the order of magnitude is correct).

Thank you 😊

tkchia commented 3 years ago

Hello @ladmanj,

But I'm getting these errors:

For example, the function SIZEOF(.text) in the linkerscript returns wrong value.

Please give more information about what you were trying to do. Because, unfortunately, I cannot read minds, and I especially cannot read minds from a distance. I cannot guess what exactly you were doing, based only on what you just said.

What would be useful is if you give me your complete input(s) and your complete command line(s) that led to the problems --- enough information so that the rest of us can reproduce the problem on our setups.

If for whatever reason you cannot send your entire inputs, try to come up with smaller inputs that exhibit the same problems you are facing, and send those.

Thank you!

ladmanj commented 3 years ago

Hello @ladmanj,

But I'm getting these errors:

For example, the function SIZEOF(.text) in the linkerscript returns wrong value.

Please give more information about what you were trying to do. Because, unfortunately, I cannot read minds, and I especially cannot read minds from a distance. I cannot guess what exactly you were doing, based only on what you just said.

What would be useful is if you give me your complete input(s) and your complete command line(s) that led to the problems --- enough information so that the rest of us can reproduce the problem on our setups.

If for whatever reason you cannot send your entire inputs, try to come up with smaller inputs that exhibit the same problems you are facing, and send those.

Thank you!

Ok, this is the whole project. Please read the few comments in gdbstub.ld.in first. In the files aren't archived all the attempts I've made, these are lost now.

ia16_ld_problem.zip

Thank you

tkchia commented 3 years ago

Hello @ladmanj,

I have uploaded a modified Makefile and a modified gdbstub.ld.in for your code, which should help you get going a bit further.

A few things:

Thank you!

ladmanj commented 3 years ago

Thank you @tkchia.

You mentioned that nasm is not fully compatible with ia16 toolchain, can you recommend me which other assembler to use? I have no preference, I'm using nasm, because the author of the gdbstub I'm forking chosen that. Only the at&t syntax is not my cup of tea, but i can get familiar wit that too.

Best regards

Hello @ladmanj,

I have uploaded a modified Makefile and a modified gdbstub.ld.in for your code, which should help you get going a bit further.

A few things:

* The `-msegelf` scheme is unfortunately still not supported by `nasm`.  (`segelf` was actually proposed by none other than the `nasm` maintainer himself, Mr. Anvin, but he has not yet implemented it there.)  So if you want to link with `nasm` code, you have to use `-mno-segelf` for now.

* When specifying memory areas, you _need_ to always explicitly think about the offsets (in the segment`:`offset  addressing scheme) that you want your code to use, even if the offsets will simply be 0.  You cannot just say `0xfa700` and expect the linker to magically guess whether it means `0xf000:0xa700`, or `0xfa70:0x0000`, or something else.  (The linker does not know how to read minds either...)

  * See the `MEMORY` command in the modified linker script to see how to represent segment`:`offset's for the `-mno-segelf` scheme.

* If you use the "small" memory model (`-mcmodel=small`), you _can_ have your data segment _separate_ from your text segment (mostly this means `ds` = `ss` ≠ `cs`).  However, the read-only data (`.rodata`) should be addressable from the same data segment.  Again, as always, you must think explicitly about offsets within segments when figuring out how to lay out your code and data segments.

* Also, if you are using `nasm`, you probably also have the disassembler `ndisasm` installed.  Use it!  Run it on your output file to get an idea of what code is generated.

Thank you!

tkchia commented 3 years ago

Hello @ladmanj,

You can use nasm, just not with -msegelf for now, because this option is implemented only in the gcc-ia16 toolchain.

Thank you!

ladmanj commented 3 years ago

Hello @tkchia,

Regarding the Makefile you modified for me - you have deleted the long paths to CC and other tools - of course to be able use your own installation.

I have the long paths because i was unable to 'make install' the tools I've built by your script from build-ia16 on ubuntu 20.10, so I'm pointing to the folder where it was built.

If you know what the issue can be, please help. But I don't remember the particular step which failed and you also don't have a crystal ball as you mentioned few times :-)

Thanks

ladmanj commented 3 years ago

Hello @ladmanj,

You can use nasm, just not with -msegelf for now, because this option is implemented only in the gcc-ia16 toolchain.

Thank you!

Hi I did understand it the first time, but the question was meant as "do you think I've better use some other asm and stay with -msegelf, and which one will be the recommended one?".

EDIT: Oh I see now, only the as contained in ia16 can be used with -msegelf, because ... this option is implemented only in the gcc-ia16 toolchain.

I'm sorry.

Thank you

tkchia commented 3 years ago

Hello @ladmanj,

If you know what the issue can be, please help.

No, there is no problem on your end. You can directly add .../prefix/bin --- which is where build-ia16 "installs" everything --- to your $PATH.

Alternatively, if you are using Ubuntu 18.04 or 20.04, I would recommend that you simply install the packages in my Ubuntu PPA. These should be much more stable. Also, these will be installed in the usual places (/usr/bin/ etc.).

Thank you!

ladmanj commented 3 years ago

Alternatively, if you are using Ubuntu 18.04 or 20.04, I would recommend that you simply install the packages in my Ubuntu PPA. These should be much more stable. Also, these will be installed in the usual places (/usr/bin/ etc.).

Unfortunately not, I'm usually an early adopter and have already switched to ubuntu 20.10.

I will do the manual PATH modification - good point.

Thanks

ladmanj commented 3 years ago

Hi @tkchia,

Oh this is great!!! I had no idea of this linker capabilities, but I was asking for a documentation how the offsets are correctly defined.

MEMORY
{
    // These are for absolute physical addresses
    ram (!RX) : ORIGIN = DATA_SEG * 0x10 + DATA_OFFSET,
            LENGTH = DATA_LENGTH
    rom (RX) : ORIGIN = BASE_SEG * 0x10 + BASE_OFFSET,
           LENGTH = BASE_LENGTH 

    // These are for offsets relative to the respective segments
    ramoff (!RX) : ORIGIN = DATA_OFFSET, LENGTH = DATA_LENGTH
    romoff (RX) : ORIGIN = BASE_OFFSET, LENGTH = BASE_LENGTH 
}

Thank you!

ladmanj commented 3 years ago

Hello @tkchia,

Your Makefile and linkersctript seem to be great, but there is an problem left.


; Initialize rw data
initmem:
    mov     di,_data
    mov     cx,_edata
    sub     cx,_data
    mov     si,_etext
    rep     movsb

; Clear bss
    mov     di,_bstart
    mov     cx,_bend
    sub     cx,_bstart
    mov     al,0
    rep     stosb
    retn

Leads to:


00000035 <initmem>:
  35:   bf 00 14                mov    di,0x1400
  38:   b9 1d 14                mov    cx,0x141d
  3b:   81 e9 00 14             sub    cx,0x1400
  3f:   be 54 00                mov    si,0x54
  42:   f3 a4                   rep movs BYTE PTR es:[di],BYTE PTR ds:[si]
  44:   bf 1e 14                mov    di,0x141e
  47:   b9 60 14                mov    cx,0x1460
  4a:   81 e9 1e 14             sub    cx,0x141e
  4e:   b0 00                   mov    al,0x0
  50:   f3 aa                   rep stos BYTE PTR es:[di],al
  52:   c3                      ret    
  53:   90                      nop

This is almost OK, only 3f: be 54 00 mov si,0x54 is a nonsense. 0x54 isn't the LMA of the .data section, where the in linkerscript defined symbol _etext should point to.

Interresting fact is, that in the binary file which I'm getting by ia16-elf-objcopy -j .text* -j .rodata* -j .data* --output-target=binary gdbstub.elf gdbstub.bin the start of initialization data seems to be right after the .text and .rodata content.

The computation of _etext = . ; by linker seems to be wrong as I was concerned already yesterday.

Thank you

ladmanj commented 3 years ago

Hi @tkchia

I have partly succeded with

SECTIONS {

        .text :
        {
        *(.text) ; *(.text*) ;
        _etext = . ;

        } >romoff AT>rom

        .data : 
        {
        _data = . ;
        *(.rodata) ; *(.rodata*) ;
        *(.data) ; *(.data*) ;
        _edata = . ;
        } >ramoff AT>rom

        .bss :
        {
        _bstart = . ;
        *(.bss) *(COMMON)
        _bend = . ;
        } >ramoff AT>ram

The addresses in disassembly are looking really good, and the initialization data is where it should be in the ROM image. But this function still doesn't work and i can't see any error:

#define EOF (-1)
const char digits[] = "0123456789abcdef";

char dbg_get_digit(int val)
{
    if ((val >= 0) && (val <= 0xf)) {
      return digits[val];
    } else {
        return EOF;
    }
}

Compiled as:

00000133 <dbg_get_digit>:
 133:   89 e3                   mov    bx,sp
 135:   8b 5f 02                mov    bx,WORD PTR [bx+0x2]
 138:   b0 ff                   mov    al,0xff
 13a:   83 fb 0f                cmp    bx,0xf
 13d:   77 04                   ja     143 <dbg_get_digit+0x10>
 13f:   8a 87 00 14             mov    al,BYTE PTR [bx+0x1400]
 143:   c3                      ret    

The string is at this address: 00001400 g O .data 00000011 digits

EDIT: Both SS, DS, ES are set to 0xff00.

I can't understand what's wrong. I will run it in simulator next evening, but now it's almost 3 AM and I must go to sleep immediately.

Thank you.

ladmanj commented 3 years ago

Uff, this one is solved, originally i didn't realize that the init data next after the .text is reachable at by cs not the default ds.

initmem:
; Initialize rw data 
    mov di,_data
    mov cx,_edata
    sub cx,_data
    mov si,_etext 
    rep cs movsb        <--- magic cs here

; Clear bss
    mov di,_bstart
    mov cx,_bend
    sub cx,_bstart
    mov al,0
    rep stosb
    retn

Yes, completely my fault - but completely invisible for me :-(

Thank you for patience.

ladmanj commented 3 years ago

Hi all For your interest, I'm able now to do single instruction step, continue and memory examination in GDB, connected via serial port to gdb-server running on my hardware.

I have still problems continuing from different than original address of interruption and register updates, but maybe I will solve it soon. Regards

tkchia commented 3 years ago

@ladmanj : looks like you are making progress. :-)

ladmanj commented 3 years ago

Hi all

Please, what's the best way to read byte from arbitrary memory address from the C function (using inline asm) addressed by 32 bit integer?

I was trying to split the 32bit integer (with 19 or 20 valid bits) to segment and offset and then inline asm to push ss and load it with the segment, then use ordinary 16bit pointer access in C and then inline asm to pop the original ss, but I failed to do so.

I don't understand the inline asm syntax, even looking to gcc manual :-( https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#OutputOperands

Thanks for help

Jakub

ladmanj commented 3 years ago

Hi

Maybe I should use far pointers and leave it in C only, but how? I can't find any documentation again what's the usage of such pointers :-(

Thanks J.

ladmanj commented 3 years ago

Hi It seems that *val = *(__far volatile char *)addr; is working, but I don't know if it's correct or not. J.

tkchia commented 3 years ago

Hello @ladmanj ,

It seems that *val = *(__far volatile char *)addr; is working, but I don't know if it's correct or not.

That should be fine. Note that addr here needs to be a segment:offset pair expressed as a 32-bit integer --- high 16 bits are the segment, low 16 bits are the offset.

addr should not be a flat absolute address. If you want to read from a flat absolute address, you must transform it into a segment:offset form first.

I don't understand the inline asm syntax, even looking to gcc manual :-( https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#OutputOperands

Basically you specify these things:

This is a very powerful inline assembly facility --- it allows inline assembly to jive with GCC's optimizer. But admittedly yes, it is a bit hard to use: you need to specify the inputs, outputs, and clobbers very precisely so that GCC does not produce incorrect code.

If you are not sure about using inline assembly, just write a separate assembly language module.

push ss and load it with the segment,

Erm, you probably do not want to mess with %ss.

Thank you!

ladmanj commented 3 years ago

Hello @tkchia

Thank you for the advice. I didn't know that the the __far pointer must be consisting of segment:offset pair. From my amateur point of view, the flat memory address can be broken down in a arbitrary way providing addr=16*seg+ofs. Is that true or is there some limitation? The only limitation I see now is that the offset must not wrap in case of accessing an array.

It comes to my mind right now, that I must figure out whether gdb sends split address or flat memory address first in the RSP packet.

Thank you

Ps: maybe i will finally remember to not mess with SS, this time.

tkchia commented 3 years ago

Hello @ladmanj,

From my amateur point of view, the flat memory address can be broken down in a arbitrary way providing addr=16*seg+ofs. Is that true or is there some limitation? The only limitation I see now is that the offset must not wrap in case of accessing an array.

That is the case, at least if you will only be addressing the first 1 MiB or memory in real mode --- this will always be the case on the 8086 or 80186.

(If, perhaps in the future, you want to access the HMA above 1 MiB or use protected mode on an 80286, then things are bit more complicated.)

Thank you!

ladmanj commented 3 years ago

Hello @ladmanj,

From my amateur point of view, the flat memory address can be broken down in a arbitrary way providing addr=16*seg+ofs. Is that true or is there some limitation? The only limitation I see now is that the offset must not wrap in case of accessing an array.

That is the case, at least if you will only be addressing the first 1 MiB or memory in real mode --- this will always be the case on the 8086 or 80186.

(If, perhaps in the future, you want to access the HMA above 1 MiB or use protected mode on an 80286, then things are bit more complicated.)

Thank you!

I am modifying gdb-stub that's originaly targeted to real mode (only) on 386 and higher to work on 8086 only. If somebody will want to add support of 286, it will be a separate task.

Now there is single byte access to arbitrary address in the 1 MiB space, so the address could be break down to seg an ofs in arbitrary way. That's done now.

Honestly, I have absolutely no clue how to break it in the case of memory larger than 1MiB.

Thank you

ladmanj commented 2 years ago

Hi @tkchia and all others

I am back for a while after a while :-) And again lost in the woods ...

I'm trying to reuse memory tester code I successfully used on other embedded platform for my not-PC-compatible board vith 8088 CPU.

Here's my make output:

$ make
ia16-elf-gcc -o memtest.ld -x c -P -E \
        -DBASE_SEG=0xf800 \
        -DDATA_SEG=0x0000 \
        -DBASE_OFFSET=0 \
        -DDATA_OFFSET=0 \
        -DBASE_LENGTH=0x8000 \
        -DDATA_LENGTH=0x1800 \
        memtest.ld.in
ia16-elf-gcc -mcmodel=small -Werror -Os -ffunction-sections -fno-stack-protector -Iarch_8086 -I/home/ladmanj/workspace/rwt_memtest -march=i8088 -mno-segelf -o main.o -c main.c
ia16-elf-gcc -mcmodel=small -Werror -Os -ffunction-sections -fno-stack-protector -Iarch_8086 -I/home/ladmanj/workspace/rwt_memtest -march=i8088 -mno-segelf -o memtest.o -c memtest.c
ia16-elf-gcc -mcmodel=small -Werror -Os -ffunction-sections -fno-stack-protector -Iarch_8086 -I/home/ladmanj/workspace/rwt_memtest -march=i8088 -mno-segelf -o console.o -c console.c
ia16-elf-gcc -mcmodel=small -Werror -Os -ffunction-sections -fno-stack-protector -Iarch_8086 -I/home/ladmanj/workspace/rwt_memtest -march=i8088 -mno-segelf -o arch_8086/io.o -c arch_8086/io.c
nasm -o arch_8086/init.o -felf arch_8086/init.nasm
ia16-elf-ld -L/home/ladmanj/DataDisk/src/build-ia16-master/prefix/lib/gcc/ia16-elf/6.3.0/ -lgcc --script=memtest.ld -Map=memtest.map --verbose -melf_i386 -N -o memtest.elf main.o memtest.o console.o arch_8086/io.o arch_8086/init.o
GNU ld (GNU Binutils) 2.32.0.20190814
  Supported emulations:
   elf_i386_msdos_mz
   elf_i386
   i386elks
   i386msdos
using external linker script:
==================================================
MEMORY
{
 ram (!RX) : ORIGIN = 0x0000 * 0x10 + 0,
      LENGTH = 0x1800
 rom (RX) : ORIGIN = 0xf800 * 0x10 + 0,
     LENGTH = 0x8000
 boot (RX) : ORIGIN = 0xffff0, LENGTH = 0x10
 ramoff (!RX) : ORIGIN = 0, LENGTH = 0x1800
 romoff (RX) : ORIGIN = 0, LENGTH = 0x8000
 bootoff (RX) : ORIGIN = 0x7ff0, LENGTH = 0x10
}
SECTIONS {
  .text :
  {
  *(.text) ; *(.text*) ;
  _etext = . ;
  } >romoff AT>rom
  .data :
  {
  _data = . ;
  *(.rodata) ; *(.rodata*) ;
  *(.data) ; *(.data*) ;
  _edata = . ;
  } >ramoff AT>rom
  .bss :
  {
  _bstart = . ;
  *(.bss) *(COMMON)
  _bend = . ;
  } >ramoff AT>ram
  .boot :
  {
  *(.boot) ; *(.boot*) ;
  } >bootoff AT>boot
 /DISCARD/ : {
  *(.comment)
  *(.note.GNU-stack)
  *(.eh_frame)
  *(.rela.eh_frame)
  *(.shstrtab)
  *(.symtab)
  *(.strtab)
 }
}

==================================================
ia16-elf-ld: mode elf_i386
attempt to open /home/ladmanj/DataDisk/src/build-ia16-master/prefix/lib/gcc/ia16-elf/6.3.0//libgcc.so failed
attempt to open /home/ladmanj/DataDisk/src/build-ia16-master/prefix/lib/gcc/ia16-elf/6.3.0//libgcc.a succeeded
/home/ladmanj/DataDisk/src/build-ia16-master/prefix/lib/gcc/ia16-elf/6.3.0//libgcc.a
attempt to open main.o succeeded
main.o
attempt to open memtest.o succeeded
memtest.o
attempt to open console.o succeeded
console.o
attempt to open arch_8086/io.o succeeded
arch_8086/io.o
attempt to open arch_8086/init.o succeeded
arch_8086/init.o
ia16-elf-ld: console.o: in function `xprintf':
(.text.xprintf+0x154): undefined reference to `__umodsi3'
ia16-elf-ld: (.text.xprintf+0x167): undefined reference to `__udivsi3'
ia16-elf-ld: link errors found, deleting executable `memtest.elf'
make: *** [Makefile:68: memtest.elf] Error 1
rm memtest.o console.o arch_8086/init.o main.o arch_8086/io.o

The umodsi3 and udivsi3 functions are unreachable even I have tried everything i found in every regarding topic here on github. Please look in the makefile how the path to libgcc.a is determined.

Please help.

Whole project is attached.

Thank you!

memtest88.tar.gz


$ ia16-elf-gcc -v
Using built-in specs.
COLLECT_GCC=ia16-elf-gcc
COLLECT_LTO_WRAPPER=/home/ladmanj/DataDisk/src/build-ia16-master/prefix/libexec/gcc/ia16-elf/6.3.0/lto-wrapper
Target: ia16-elf
Configured with: ../gcc-ia16/configure --target=ia16-elf --prefix=/home/ladmanj/DataDisk/src/build-ia16-master/prefix --enable-libssp --enable-languages=c,c++ --with-newlib --disable-libstdcxx-dual-abi --disable-extern-template --disable-wchar_t --disable-libstdcxx-verbose --disable-libquadmath --with-gmp=/home/ladmanj/DataDisk/src/build-ia16-master/prefix-gmp --with-mpc=/home/ladmanj/DataDisk/src/build-ia16-master/prefix-mpc --with-mpfr=/home/ladmanj/DataDisk/src/build-ia16-master/prefix-mpfr --with-isl=/home/ladmanj/DataDisk/src/build-ia16-master/prefix-isl
Thread model: single
gcc version 6.3.0 (GCC)
$ ia16-elf-ld -v
GNU ld (GNU Binutils) 2.32.0.20190814
asiekierka commented 1 year ago

Here's a few rambling thoughts as I work with gcc-ia16 on a platform which is very ROM-centric, with little RAM:

Thank you for your hard, hard work. Have you considered a way to donate towards future development efforts?

(Also, it might be a good idea to enable GitHub's Discussions feature to provide non-bug-report/feature-request user forums, as opposed to this issue)

ghaerr commented 1 year ago

Hello @asiekierka,

When writing platform-specific code, I'd think generating a .fartext/.farrodata segment per compilation unit - like many 8086 compilers seem to do - would be much more economical...

I'm not sure what the difference would be, using one segment per function or compilation unit - the linker script ends up placing all the functions in one of two far text segments in the end anyways (for a maximum of 128K code).

once the ability to detect being in the same segment were to be implemented - as it wouldn't need to reach to another segment, not always anyway.

I'm not sure about this either, since far code will always end up being in one of two far segments, and near code won't ever be mixed in. Since the segment can't be known at compile time (unless its a near function or a non-standard linker script were used with in conjunction with .section function attributes), all far functions are compiled to be called the same way, using far prologue/epilogues.

Thank you!

asiekierka commented 1 year ago

I'm not sure what the difference would be, using one segment per function or compilation unit - the linker script ends up placing all the functions in one of two far text segments in the end anyways (for a maximum of 128K code).

I'm using my own linker script, as I'm targetting a non-DOS/ELKS platform... With segelf enabled on the medium memory model (I might have a mistake somewhere), each function seems to be padded to a 16-byte boundary, which feels a little wasteful.

I'm not sure about this either, since far code will always end up being in one of two far segments, and near code won't ever be mixed in.

It's about far data, not far code. It would make more sense if the compiler mechanisms proposed in https://github.com/tkchia/gcc-ia16/issues/79 were implemented - this would make it easy to access data in the same section as the code with a mere segment override; an option for per-compilation-unit sections would then make it easier for end-users to benefit from the optimization without manually planning out sections, though I admit the benefit here is negligible.

asiekierka commented 1 year ago

I've partially worked around putting every function in its own segment by digging into ia16.c and realizing that -fno-function-sections will also put every file in its own segment instead. I wonder if it's possible to decouple the two, but for now I achieved what I wanted to - a ~2-3% reduction in total filesize and a tiny speed boost (on V30MZ, a far call takes 10 cycles, but PUSH CS + a near call takes only 7).

asiekierka commented 1 year ago

About jump tables, I've made a patch to put them in the .text section and adjust the emitted jmp to %cs accordingly; however, I'm entirely not sure if it's upstream-quality.