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
173 stars 13 forks source link

Far function pointer calls violate %ds = .data invariant #120

Open asiekierka opened 1 year ago

asiekierka commented 1 year ago

Test case:

#include <stdio.h>

typedef void (*oop_command_proc)(void);

static void test1(void) {
    printf("test1\n");
}

static void test2(void) {
    printf("test2\n");
}

static void test3(void) {
    printf("test3\n");
}

static const oop_command_proc __far oop_procs[] = {
    test1,
    test2,
    test3
};

int main(int argc, char** argv) {
    if (argc >= 2) {
        oop_procs[argv[1][0] - '0']();
    }
    return 0;
}

ia16-elf-gcc -mcmodel=medium -o testcase.exe testcase.c gives the expected result, which is: testcase.exe 0 => prints test1, testcase.exe 1 => prints test2, testcase.exe 2 => prints test3.

On any optimization level (tested -O1, -O2, -Os), running any of the above commands results in a DOS freeze.

Tested on the latest version of build-ia16 from PPA; can also reproduce on my own WonderSwan builds. A workaround is to use __attribute__((optimize("-O0"))) on affected functions.

tkchia commented 1 year ago

Hello @asiekierka,

Confirmed. The bug is that the call is performed with %ds.data (the default data segment) even though the callee expects %ds = .data.

main:
    ...
    movw    8(%bp), %bx
    movw    2(%bx), %bx
    movb    (%bx),  %al
    cbtw
    movb    $2, %cl
    shlw    %cl,    %ax
    xchgw   %ax,    %bx
    movw    $oop_procs@OZSEG16, %ax
    movw    %ax,    %ds
    lcall   *oop_procs-192(%bx)
    ...

I may need some time to figure out how to properly fix this.

Thank you!

asiekierka commented 1 year ago

I changed the name of the bug accordingly, as I have found a different case in which this issue occured.

asiekierka commented 1 year ago

One workaround that comes to mind is allocating %es in such a scenario, and using an %es segment override on lcall.

(I can move to Codeberg, if you prefer.)