bebbo / libnix

libnix (v4): a C link library for AmigaOS/m68k
14 stars 9 forks source link

Possible memory corruption originating from libnix13 #84

Closed mankeli closed 1 week ago

mankeli commented 4 weeks ago

A mystery blit corrupts chip memory before main() in binary compiled with bebbo-gcc. Investigation by a/b in this EAB thread suggests that there's DOS I/O calls happening when system is disabled.

The code in main() also disables system, but doesn't do any I/O afterwards. I've verified that the chip data is loaded into memory, but then gets stomped by the blit.

CFLAGS for compiling are -mcrt=nix13 -O2 -Wall -mtune=68000. I tried to look for obvious problem in libnix, but could find anything definitive. Stackswap seems to disable system for a short time, and command line parsing uses some Dos calls, and both are added to the libc init list, but not sure why the memory corruption happens.

bebbo commented 4 weeks ago

sorry, that's not enough info to do anything

bebbo commented 4 weeks ago
40a10b7c :   007c 4e5d            ORSR.W #$4e5d
40a10b80 :   4e75                 RTS.L
40a10b82 :   303c 0f0f            MOVE.W #$0f0f,d0
40a10b86 :   33c0 00df f180       MOVE.W d0,$00dff180
40a10b8c :   33c0 00df f180       MOVE.W d0,$00dff180
40a10b92 :   60f2                 BT.B #$f2
40a10b94 :   2f0a                 MOVE.L a2,-(a7) [40000014]
40a10b96 :   700a                 MOVE.L #$0a,d0
40a10b98 : * 21c0 0090            MOVE.L d0,$0090.w [00f80c4c]
40a10b9c :   4eb9 40a1 73c8       JSR.L $40a173c8
40a10ba2 :   33fc 7fff 00df f09a  MOVE.W #$7fff,$00dff09a
40a10baa :   33fc 7fff 00df f09c  MOVE.W #$7fff,$00dff09c
40a10bb2 :   33fc 7ff0 00df f096  MOVE.W #$7ff0,$00dff096
40a10bba :   33fc 0000 00df f102  MOVE.W #$0000,$00dff102
40a10bc2 :   3039 00df f004       MOVE.W $00dff004,d0
40a10bc8 :   0800 0000            BTST.L #$0000,d0
40a10bcc :   67f4                 BEQ.B #$f4

writing at address 0x00000090 is not part of libnix.

mankeli commented 4 weeks ago

No, it most certainly is not part of libnix, but it should be safe to write there on Amiga. (68000 trap vector area)

It is there to get memwatch breakpoint triggered in the limited UAE debugger, to verify that the memory stomping indeed happens before any "user code" is reached. I'm gonna investigate it further, and possibly find a workaround. Just wanted to know if you have any thoughts about it.

mankeli commented 4 weeks ago

adding void __nocommandline(){}; override to demo code seems to fix the wb startup!

bebbo commented 4 weeks ago

I guess you already disabled __initlibraries.

mankeli commented 3 weeks ago

I guess you already disabled __initlibraries.

Yeah I tried - it gives "Software error - task held" error from both cli and wb

bebbo commented 3 weeks ago

I guess you already disabled __initlibraries.

Yeah I tried - it gives "Software error - task held" error from both cli and wb

You should only tinker with internal topics if you are familiar with them and know the consequences.

__nocommandline requires a valid DOSBase and is called before your main is called. It relies on the fact that __initlibraries run before. And there are more functions which require the DOSBase or maybe a different library to be present already.

This isn't a bug in libnix, it's rather a wrong use of libnix.

mankeli commented 3 weeks ago

Yeah I didn't try it [ what __initlibraries does ] very throughly, but I think the bug with cmd line parsing is real. Not sure what causes it though.

bebbo commented 3 weeks ago

An out of the box kick13 hello world runs without problems from CLI and Workbench. And it's calling __initlibraries plus __nocommandline.

Please provide some source with make instructions to prove your claim.

mankeli commented 1 week ago

Okay. Sorry for the delay, I've been busy. But finally took some time to strip down one of my programs to somewhat minimal test case. I've only tested it on 512/512 A500.

Compilation spell: /opt/amiga/bin/m68k-amigaos-gcc -mcrt=nix13 -O0 -Wall demo.c -o demo.exe

#include <stdio.h>
#include <clib/exec_protos.h>
#include <hardware/custom.h>
#include <hardware/cia.h>
#include <stdbool.h>
extern volatile struct Custom custom;
#define CUSTO(__field)    (uint16_t)(uintptr_t)(&(((struct Custom *) 0)->__field))

//void __nocommandline(){};

void showred()
{
    while(1)
    {
        custom.color[0] = 0x830;
        custom.color[0] = 0x420;
        custom.color[0] = 0x820;
        custom.color[0] = 0x410;
        custom.color[0] = 0x810;
        custom.color[0] = 0x410;
        custom.color[0] = 0x800;
        custom.color[0] = 0x600;
        custom.color[0] = 0xC00;
        custom.color[0] = 0x800;
        custom.color[0] = 0xF00;
        custom.color[0] = 0x800;
        custom.color[0] = 0xC00;
        custom.color[0] = 0x600;
        custom.color[0] = 0x810;
        custom.color[0] = 0x420;
    }
}

void showgreen()
{
    while(1)
    {
        custom.color[0] = 0x083;
        custom.color[0] = 0x042;
        custom.color[0] = 0x082;
        custom.color[0] = 0x041;
        custom.color[0] = 0x081;
        custom.color[0] = 0x041;
        custom.color[0] = 0x080;
        custom.color[0] = 0x060;
        custom.color[0] = 0x0C0;
        custom.color[0] = 0x080;
        custom.color[0] = 0x0F0;
        custom.color[0] = 0x080;
        custom.color[0] = 0x0C0;
        custom.color[0] = 0x060;
        custom.color[0] = 0x081;
        custom.color[0] = 0x042;
    }
}

static __chip uint16_t copperlist1[] =
{
    0x01FE, 0x0000,
    CUSTO(bplpt[0])+0, 0x0000,
    CUSTO(bplpt[0])+2, 0x0000,
    CUSTO(bplpt[1])+0, 0x0000,
    CUSTO(bplpt[1])+2, 0x0000,
    CUSTO(bplpt[2])+0, 0x0000,
    CUSTO(bplpt[2])+2, 0x0000,
    CUSTO(bplpt[3])+0, 0x0000,
    CUSTO(bplpt[3])+2, 0x0000,

    CUSTO(bpl1mod), 3*40,
    CUSTO(bpl2mod), 3*40,

    CUSTO(bplcon0), 0x0000,

//  0x6001, 0xFFFE,
    CUSTO(bplcon0), 0x7800,
    CUSTO(bplcon1), 0x8800,

    CUSTO(color[0]), 0x0000,

    0x4e01, 0xFFFE,
    CUSTO(bplcon0), 0x0000,

    CUSTO(color[0]), 0x0000,
    0x4e01, 0xFFFE,
    CUSTO(color[0]), 0x0111,
    0x7d01, 0xFFFE,
    CUSTO(color[0]), 0x0222,
    0x7e01, 0xFFFE,
    CUSTO(color[0]), 0x0111,
    0x7f01, 0xFFFE,
    CUSTO(color[0]), 0x0222,
    0x8d01, 0xFFFE,
    CUSTO(color[0]), 0x0111,
    0x8e01, 0xFFFE,
    CUSTO(color[0]), 0x0222,
    0x8f01, 0xFFFE,
    CUSTO(color[0]), 0x0111,

    0xfe01, 0xFFFE,

    CUSTO(color[0]), 0x0000,
    CUSTO(bplcon0), 0x0000,

    CUSTO(bplpt[0])+0, 0x0000,
    CUSTO(bplpt[0])+2, 0x0000,
    CUSTO(bplpt[1])+0, 0x0000,
    CUSTO(bplpt[1])+2, 0x0000,
    CUSTO(bplpt[2])+0, 0x0000,
    CUSTO(bplpt[2])+2, 0x0000,
    CUSTO(bplpt[3])+0, 0x0000,
    CUSTO(bplpt[3])+2, 0x0000,
    CUSTO(bplpt[4])+0, 0x0000, // AGA
    CUSTO(bplpt[4])+2, 0x0000, // AGA
    CUSTO(bplpt[5])+0, 0x0000, // AGA
    CUSTO(bplpt[5])+2, 0x0000, // AGA

    0xff01, 0xFFFE,

    // vv do not move!

    CUSTO(ddfstrt), 0x0038,

    CUSTO(bplcon0), 0x7800,
    CUSTO(bplcon1), 0x0000,

    CUSTO(bpl1mod), 3*40,
    CUSTO(bpl2mod), 3*40,

    CUSTO(intreq), 0x8010,

    CUSTO(dmacon), 0x0400,

    0xff0b, 0xFFFE,

    0xffdf, 0xFFFE,

    0x0b01, 0xFFFE,
    CUSTO(dmacon), 0,

    0x2c01, 0xFFFE,
    CUSTO(color[0]), 0x0000,

    // 45 lines

    0xFFFF, 0xFFFE
};

bool searchforvalue()
{
    uintptr_t dmacon_addr = 0;

    for (int i = 0; i < sizeof(copperlist1)/2; i++)
    {
        if (copperlist1[i] == CUSTO(dmacon))
        {
            dmacon_addr = (uintptr_t)(&copperlist1[i])+3;
        }
    }

    return dmacon_addr != 0;
}

int main(void)
{
    Disable();

    custom.intena = 0x7FFF;
    custom.intreq = 0x7FFF;
    custom.dmacon = 0x7FFF;
    custom.bplcon1 = 0;

    if (searchforvalue())
        showgreen();
    else
        showred();

    return 0;
}

Precompiled testcase: nixtestcase.zip

nixtestcase.adf contains demopack.exe which should show green screen. It shows red screen if the memory has been stomped. There's startup-sequence on disk, or you can launch it manually from cli and it should show green screen.

The included wbrig.adf can be also used. Insert wbrig.adf to df0 and nixtestcase.adf to df1. It should boot to green screen. But if you move cli window during the "Waiting x" prints, the memory gets stomped and it shows the red screen. Same can be observed if you launch it from regular wb. It might also guru.

As I said before, enabling void __nocommandline(){}; seems to fix it.

mankeli commented 6 days ago

@bebbo should this ticket be re-opened?

bebbo commented 6 days ago

@bebbo should this ticket be re-opened?

not needed, it's fixed now: The lock is null, which wasn't checked.

mankeli commented 6 days ago

is it fixed in libnix13 too?

bebbo commented 6 days ago

is it fixed in libnix13 too?

yes, you need to run a make update && make libnix