RISCV Global object constructors are not being called

0

I am running into a similar problem to this post: Global constructor call not in .init_array section

I will re-use his example, but I think this is a problem specific to the RISCV environment, which is why I am creating a new post.

class foobar
{
    int i;

public:
    foobar()
    {
        i = 100;
    }

    void inc()
    {
        i++;
    }
};

foobar foo;

int main()
{
    foo.inc();
    for (;;);
}

The issue is that the constructor to foo is never called. Which I put a breakpoint on the first increment, the value of i is 0, not the expected 100.

Here is the output of: riscv64-unknown-elf-objdump.exe -j .init_array -x objs/main.o

objs/main.o: file format elf32-littleriscv objs/main.o architecture: riscv:rv32, flags 0x00000011: HAS_RELOC, HAS_SYMS start address 0x00000000

Sections: Idx Name Size VMA LMA File off Algn 8 .init_array 00000004 00000000 00000000 00000154 2**2 CONTENTS, ALLOC, LOAD, RELOC, DATA SYMBOL TABLE: 00000000 l d .init_array 00000000 .init_array

RELOCATION RECORDS FOR [.init_array]: OFFSET TYPE VALUE 00000000 R_RISCV_32 _GLOBAL__sub_I_foo

Which leads me to believe that it should be called? I have also tested standard C variables declared globally, which do get assigned and also show up on the .init_array.

My _init() looks like this:

void _init(void)
{
    copy_section(&__sdata_load, &__sdata_start, &__sdata_end);
    copy_section(&__data_load, &__data_start, &__data_end);
    zero_section(&__sbss_start, &__sbss_end);
    zero_section(&__bss_start, &__bss_end);

    exit(main());
}

It looks like other RISCV based projects also do not leverage libc initialization primitives (like __libc_init_array()), as a bonus question I was wondering why that is?

c++
constructor
linker
global-variables
riscv
asked on Stack Overflow Mar 2, 2018 by FeelTheBurns • edited Mar 13, 2018 by FeelTheBurns

1 Answer

1

I finally put together a proper solution to this problem I faced all those months ago. Here is what the I ended up putting into the initialization process. This is called right before main(). This is largely influenced from the solution that was brought up in the post I linked in my original question.

extern void (**__preinit_array_start)();
extern void (**__preinit_array_end)();
extern void (**__init_array_start)();
extern void (**__init_array_end)();
extern void (**__fini_array_start)();
extern void (**__fini_array_end)();

static void execute_array(void (** _start)(), void (** _end)())
{
    size_t count;
    size_t i;

    count = _end - _start;
    for (i = 0; i < count; i++)
    {
        (*_start[i])();
    }
}

void _init(void)
{
    execute_array(__preinit_array_start, __preinit_array_end);
    execute_array(__init_array_start, __init_array_end);

    main();
}

void _fini()
{
    execute_array(__fini_array_start, __fini_array_end);
}
answered on Stack Overflow Aug 27, 2018 by FeelTheBurns

User contributions licensed under CC BY-SA 3.0