nice_remark
nice_remark

Reputation: 337

Return a structure that was created within a function?

As stated in the question, is it possible to create a structure within a function, and then return that structure when the function exits? Since the structure is not created until the function is called, I don't know what to put in the prototype for the return value. Any advice/help would be great, thanks.

static void section_to_segment_map(Elf *elf, GElf_Ehdr *ehdr) {

    struct memory_data {
        int phdr_addrs[ehdr->e_phnum][2];
        int section_bounds[ehdr->e_shnum][2];
    } memData;

    for(int phead_cnt = 0; phead_cnt < ehdr->e_phnum; phead_cnt++) {
        GElf_Phdr mem;
        GElf_Phdr *phdr = gelf_getphdr(elf, phead_cnt, &mem);

        memData.phdr_addrs[phead_cnt][1] = phdr->p_vaddr;
        memData.phdr_addrs[phead_cnt][2] = phdr->p_vaddr + phdr->p_memsz;

    }
    printf("Starting and Ending Address Values for Program Segments:\n");
    for(int i = 0; i < ehdr->e_phnum; i++)
       printf("%x --> %x\n", memData.phdr_addrs[i][1], memData.phdr_addrs[i][2]);

    Elf_Scn *scn = NULL;
    for(int shead_cnt = 0; shead_cnt < ehdr->e_shnum; shead_cnt++) {
        scn = elf_getscn(elf, shead_cnt);
        GElf_Shdr shdr_mem;
        GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem);

        memData.section_bounds[shead_cnt][1] = shdr->sh_addr;
        memData.section_bounds[shead_cnt][2] = shdr->sh_addr + shdr->sh_size;
    }
    printf("\n");
    printf("Starting and Ending Addresses for Program Sections:\n");
    for(int j = 0; j < ehdr->e_shnum; j++) 
        printf("%x --> %x\n", memData.section_bounds[j][1], memData.section_bounds[j][2]);

    return memData;
}

Upvotes: 1

Views: 99

Answers (2)

chux
chux

Reputation: 153338

Return a structure that was created within a function?
is it possible to create a structure within a function, and then return that structure ..?

No. The return type must be defined before the function body.

// void section_to_segment_map(Elf *elf, GElf_Ehdr *ehdr) {
struct memory_data section_to_segment_map(Elf *elf, GElf_Ehdr *ehdr) {

Yet OP's struct has a variable size and so defining the struct ahead of time fails.

struct memory_data {
    // fails  "error: variably modified 'phdr_addrs' at file scope"
    int phdr_addrs[some_variable][2];  
    ...
} memData;

A fixed sized struct would work, yet may be inefficient if large.

#define MEMORY_DATA_N_MAX 10
struct memory_data {
    int phdr_addrs[MEMORY_DATA_N_MAX][2];  
    ...
} memData;

Various dynamic options exist such as creating a struct that contains the size information and pointers to allocated space. This obliges section_to_segment_map() to allocate memory and the caller to insure it is free'd.

struct memory_data {
    size_t sz;
    int (*phdr_addrs)[2];
    int (*section_bounds)[2];
} memData;

Upvotes: 1

Idan
Idan

Reputation: 333

First of all, in order to return a structure from you function you need to declare it outside of the functions scope, so other functions would be able to use it as well.

/* You can change this size if you wish */
#define PHDR_ADDRESS_SIZE (0xffff)
struct memory_data {

        int phdr_addrs[PHDR_ADDRESS_SIZE][2];
        int section_bounds[PHDR_ADDRESS_SIZE][2];
   } memData;

static void section_to_segment_map(Elf *elf, GElf_Ehdr *ehdr)
{
/* Code... */
}

int main(void)
{
    memData m = {};
}

In order to return a structure from your function, you have two main options.

Actually return the structre

You need to cahnge the return value of the function to be from the type "memData" instead of "void". Then, you can just return that value. For example:

memData section_to_segment_map(Elf *elf, GElf_Ehdr *ehdr)
{
    memData m = {};
    /* Code... */
    return m;
}

Pass an out parameter to the function

Another option, which is more reccomended in my opinion is to pass an out parameter to the function, which is a pointer.

You need to pass a pointer to memData, and the you can change it inside your function. For example:

void section_to_segment_map(Elf *elf, GElf_Ehdr *ehdr, memData* m)
{
    for(int phead_cnt = 0; phead_cnt < ehdr->e_phnum; phead_cnt++) {
        GElf_Phdr mem;
        GElf_Phdr *phdr = gelf_getphdr(elf, phead_cnt, &mem);

        *memData.phdr_addrs[phead_cnt][1] = phdr->p_vaddr;
        *memData.phdr_addrs[phead_cnt][2] = phdr->p_vaddr + phdr->p_memsz;
    }
    /* More of the code.... */
return;
}

In order to call the function from main, you should do the following:

int main(void)
{
    memData m = {};
    /* Put your own arguments isntead of <elf>, <edhr> */
    section_to_segment_map(<elf>, <ehdr>, &m);

}

Upvotes: 0

Related Questions