1

By looking at this answer: https://stackoverflow.com/a/4671482/1770034 I can use dlsym to get a global variable in C. Is it possible to get a member from a struct.

I'm guessing that if I had the following code in a shared object:

header.h

struct myStruct
{
    int a;
    int b;
};

imp.c

struct myStruct structure = { 123, 456 };

I could include the same header.h file and cast the whole pointer to a struct myStruct*. struct myStruct * capturedStructure = (struct myStruct*) dlsym(handle, "structure");

However, is there a way to get the address to member directly. I'm guessing I'm unable to do something like: int* c = (int*) dlsym(handle, "structure.b");

Since dlsym allows a person to grab a function or global by itself (without a header), I'm hoping that I can also grab a member without requiring a header.

5
  • 4
    Pretty sure the answer is "No." That's because the member offset calculations are handled in the code, and don't appear in the symbol table. And of course you can't rely on the offset being constant for all versions of the library. Commented Jan 3, 2019 at 0:08
  • @user3386109 - Does that mean that for a given arch (ie: x86, x86_64) I am unable to use int* b = (int*) (dlsym(handle, "structure") + 4); I suppose the answer is "No" because the compiler may reorder my members to reduce padding between members. Commented Jan 3, 2019 at 0:13
  • Using fixed offsets won't work in the long run. For example version 1 of the library has int a; int b; Then version 2 of the library adds another member int a; int c; int b;. The offset to b will change. So even if you have the header for the structure, you need to use the correct version of the header for each version of the library. Commented Jan 3, 2019 at 0:16
  • 2
    BTW, although the compiler may put padding between members, it is not allowed to reorder members. Commented Jan 3, 2019 at 0:18
  • @user3386109 - Thank you I didn't realize that. I thought that you needed to use __attribute__((packed)) [in gcc] to prevent reordering, but that attribute really only prevents padding from being inserted and you assume responsibility of aligning the data correctly. Commented Jan 3, 2019 at 0:24

2 Answers 2

2

the address to member directly

The normal way looks like this:

struct myStruct *pnt = (struct myStruct*) dlsym(handle, "structure");
int *b = &pnt->b;

Now let's substitute s/pnt/((struct myStruct*) dlsym(handle, "structure"))/. That's:

int *b = &((struct myStruct*) dlsym(handle, "structure"))->b;

without the compiler having the structure defined? (from comments)

This could be a bit tricky, but we can do it. You would need to export another symbol:

const size_t offsetof_member_b_in_myStruct = offset(struct myStruct, b);

And then later in client code:

int *b = (int*)(
             (uintptr_t)dlsym(handle, "structure") + 
             *(size_t*)dlsym(handle, "offsetof_member_b_in_myStruct")
         );

I guess such API could be consistent, but feels bad. It's simpler to export the structure to client code. Maybe in a general case, better create a standard specifying memory layout of the structure you are interchanging with client code (thus you push the responsibility to clients to provide proper abstraction).

Sign up to request clarification or add additional context in comments.

7 Comments

This will work, but does the symbol table keep track of the offsets so that I can access the member "b" without the compiler having the structure defined? I can manually do int* b = (int*) (dlsym(handle, "structure") + 4);
without the compiler having the structure defined? - you can, but notice that this is wrong. Read about padding in structures. You can export offsetof(struct myStruct, b) in a variable and then (int*)((uintptr_t)dlsym(handle, "structure") + offsetof(struct myStruct, b)) but it feels crude. It is wrong to assume that offsetof(struct myStruct, b) is equal to 4.
Thank you. Yes, I didn't consider that the compiler may reorder the members to reduce padding between the elements.
@Questionable A C compiler may not reorder members of a struct.
To me it seems a lot cleaner to export a "getter" that returns the value of b.
|
1

With extern struct myStruct structure; there will be an entry in the symbol table pointing to structure and it will be keyed to the string structure.

To get the address of its b member, you simply do:

struct myStruct *p = dlsym(handle, "structure");
if(!p) fail();
int *pb = &p->b;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.