devkitPro / wut

Let's try to make a Wii U Toolchain / SDK for creating rpx/rpl.
zlib License
236 stars 52 forks source link

elf2rpl. strange behaviour with arrays and pointer from the .data section #54

Closed Maschell closed 6 years ago

Maschell commented 7 years ago

Hello, currently I'm working on RetroArch which uses just the elf2rpl to create a .rpx. But once I added my controller patcher code to add HID controller support, but when I tried the .rpx build, it crashes. I not quite sure if it's an issue of retroarch or if its related to elf2rpl.

The problem:

I have some data declared in the .data section within an own .c file.

The gControllerMapping stores information about the controller mapping, and gProPadInfo is a array of pointers, which point to parts of gControllerMapping.

The problem is, that this line will always set padinfo to NULL. It just happens at the .rpx not at the .elf. Using

ControllerMappingPADInfo * padinfo = &gControllerMapping.proController[i].pad_infos[0];

instead works perfectly.

But this gets even stranger:

I tried to simplify the issue with an short example. test1.c

    u32 valuesTest[4] __attribute__((section(".data"))) ;
    u32 * valuePointer[4] __attribute__((section(".data"))) = {   
                                    &valuesTest[0],
                                    &valuesTest[1],
                                    &valuesTest[2],
                                    &valuesTest[3]};

test1.h

    extern u32 valuesTest[4];
    extern u32 * valuePointer[4];

main.c

    for(int i=0;i<4;i++){
        printf("i: %d &valuesTest[i] %08X\n",i,&valuesTest[i]);
        printf("i: %d valuePointer %08X\n",i,valuePointer[i]);
    }
    printf("\n");

    printf("i: 1 valuePointer %08X\n",valuePointer[0]);
    printf("i: 1 valuePointer %08X\n",valuePointer[1]);
    printf("i: 2 valuePointer %08X\n",valuePointer[2]);
    printf("i: 3 valuePointer %08X\n",valuePointer[3]);

output .rpx:

    i: 0 &valuesTest[i] 10503010
    i: 0 valuePointer 00000000
    i: 1 &valuesTest[i] 10503014
    i: 1 valuePointer 00000000
    i: 2 &valuesTest[i] 10503018
    i: 2 valuePointer 00000000
    i: 3 &valuesTest[i] 1050301C
    i: 3 valuePointer 00000000

    i: 1 valuePointer 10503010
    i: 1 valuePointer 10503014
    i: 2 valuePointer 10503018
    i: 3 valuePointer 1050301C

Accessing the valuePointer [i] returns 0, but valuePointer[0] returns the actual value.

output .elf

    i: 0 &valuesTest[i] 00A79510
    i: 0 valuePointer 00A79510
    i: 1 &valuesTest[i] 00A79514
    i: 1 valuePointer 00A79514
    i: 2 &valuesTest[i] 00A79518
    i: 2 valuePointer 00A79518
    i: 3 &valuesTest[i] 00A7951C
    i: 3 valuePointer 00A7951C

    i: 1 valuePointer 00A79510
    i: 1 valuePointer 00A79514
    i: 2 valuePointer 00A79518
    i: 3 valuePointer 00A7951C

When I try the same code with the elf build everything works fine.

Sometimes the accessing works

If you change the main.c to the following and change the order of the statements, everything is working.

new_main.c

        printf("i: 1 valuePointer %08X\n",valuePointer[0]);
        printf("i: 1 valuePointer %08X\n",valuePointer[1]);
        printf("i: 2 valuePointer %08X\n",valuePointer[2]);
        printf("i: 3 valuePointer %08X\n",valuePointer[3]);

        printf("\n");

            for(int i=0;i<4;i++){
            printf("i: %d &valuesTest[i] %08X\n",i,&valuesTest[i]);
            printf("i: %d valuePointer %08X\n",i,valuePointer[i]);
        }

output .rpx

        i: 1 valuePointer 10503010
        i: 1 valuePointer 10503014
        i: 2 valuePointer 10503018
        i: 3 valuePointer 1050301C

        i: 0 &valuesTest[i] 10503010
        i: 0 valuePointer 10503010
        i: 1 &valuesTest[i] 10503014
        i: 1 valuePointer 10503014
        i: 2 &valuesTest[i] 10503018
        i: 2 valuePointer 10503018
        i: 3 &valuesTest[i] 1050301C
        i: 3 valuePointer 1050301C

It also works, if you declare valuePointer and valuesTest directly in the main.c

    u32 valuesTest[4] __attribute__((section(".data"))) ;
    u32 * valuePointer[4] __attribute__((section(".data"))) = {   &valuesTest[0],
                                &valuesTest[1],
                                &valuesTest[2],
                                &valuesTest[3]};

    void test(){
        for(int i=0;i<4;i++){
            printf("i: %d &valuesTest[i] %08X\n",i,&valuesTest[i]);
            printf("i: %d valuePointer %08X\n",i,valuePointer[i]);
        }

        printf("\n");

        printf("i: 1 valuePointer %08X\n",valuePointer[0]);
        printf("i: 1 valuePointer %08X\n",valuePointer[1]);
        printf("i: 2 valuePointer %08X\n",valuePointer[2]);
        printf("i: 3 valuePointer %08X\n",valuePointer[3]);
    }
shinyquagsire23 commented 7 years ago

Do you have an RPX which could be looked at? The last really weird issue I had with elf2rpl was with switch statements using a lookup table in .rodata which would try to have .rodata relative pointers pointing to .text without relocations, that got solved by moving .rodata to CODE with .text so the relative addresses would be valid. I suspect there might be something similar between .rodata and .data now, which could be an issue because DATA and .data has to be RW and we can't just avoid section relocation again. If this is the case, I also doubt it could be remedied with GCC or elf2rpl, but it's hard to know.

Maschell commented 7 years ago

In the attachment is the .rpx, and homebrew launcher .elf (retroarch_wiiu.elf) and .elf that was converted to the .rpx (retroarch_wiiu.rpx.elf)

I placed the following code in the function: ControllerPatcherInit (in this file)

    for(int i=0;i<4;i++){
        printf("i: %d &valuesTest[i] %08X\n",i,&gControllerMapping.proController[i].pad_infos[0]);
        printf("i: %d gProPadInfo %08X\n",i,gProPadInfo[i]);
    }
    printf("\n");

    printf("i: 1 gProPadInfo %08X\n",gProPadInfo[0]);
    printf("i: 1 gProPadInfo %08X\n",gProPadInfo[1]);
    printf("i: 2 gProPadInfo %08X\n",gProPadInfo[2]);
    printf("i: 3 gProPadInfo %08X\n",gProPadInfo[3]);

gControllerMapping and gProPadInfo are defined in a seperate file I also included the .o of the CPRetainVars.cpp and ControllerPatcherWrapper.cpp

RetroArch.zip

Like in the first post said, the HBL .elf is logging this

i: 0 &valuesTest[i] 00B51420
i: 0 gProPadInfo 00B51420
i: 1 &valuesTest[i] 00B51444
i: 1 gProPadInfo 00B51444
i: 2 &valuesTest[i] 00B51468
i: 2 gProPadInfo 00B51468
i: 3 &valuesTest[i] 00B5148C
i: 3 gProPadInfo 00B5148C

i: 1 gProPadInfo 00B51420
i: 1 gProPadInfo 00B51444
i: 2 gProPadInfo 00B51468
i: 3 gProPadInfo 00B5148C

the .rpx version this:

i: 0 &valuesTest[i] 10507420
i: 0 gProPadInfo 00000000
i: 1 &valuesTest[i] 10507444
i: 1 gProPadInfo 00000000
i: 2 &valuesTest[i] 10507468
i: 2 gProPadInfo 00000000
i: 3 &valuesTest[i] 1050748C
i: 3 gProPadInfo 00000000

i: 1 gProPadInfo 10507420
i: 1 gProPadInfo 10507444
i: 2 gProPadInfo 10507468
i: 3 gProPadInfo 1050748C

I also noticed, that disabled the compiler optimization fixes the problem. Here are the same files without optimization: RetroArch-without-o3-working.zip

shinyquagsire23 commented 7 years ago

I mean, looking at a disassembly it doesn't even load a pointer to gProPadInfo until after the for loop for some reason? Seems to be loading from some 0xFFFFFFC address I think, looks like a bad relocation. Is elf2rpl giving you any errors at all? I checked with readrpl and I'm seeing the compiled RPX attempting to index to $TEXT backwards for some reason,

02005CBE 00000106 ADDR16_HA        02000000 $TEXT + DFFFFFC
02005CC6 00000206 ADDR16_HA        10000000 $DATA + 4420
02005CCE 00000204 ADDR16_LO        10000000 $DATA + 4420
02005CD6 00000104 ADDR16_LO        02000000 $TEXT + DFFFFFC

Hard to debug this though without the .elf which was used to generate the .rpx

Maschell commented 7 years ago

"and .elf that was converted to the .rpx (retroarch_wiiu.rpx.elf)" The is already included in the zip? Or did something go wrong with the upload?

elf2rpl doesn't give any errors

shinyquagsire23 commented 7 years ago

Oh, I think I read that wrong the first time through, I suppose I'll take a look then.

exjam commented 7 years ago

This is odd... It seems to be broken before elf2rpl is even run on it by the looks of retroarch_wiiu.rpx.elf. This is maybe related to our linker script shenanigans, but I have no clue really.

exjam commented 6 years ago

Fixed in the rewrite branch.