This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
Greetings, >> Even if it was mapped as executable, it would still be undefined behaviour, >> since there is no actual code there to be executed. > > That I don't understand. If "there is no actual code there to be executed", how > could my second example (i.e., the `open_hook') succeed? You see, the > `open_hook' pointer is changed in the __attribute__((constructor)), dynamically. In your second example, you have this: open_t open_hook = NULL; /* some code that initializes open_hook */ int open(const char *pathname, int flags, ...) { ... open_hook(...); ... } When your code calls open(), the dynamic linker will try to resolve the symbol for open. It uses the function you declared there: int open(const char* pathname, int flags, ...) There is code in that function: loading what is contained in the pointer open_hook into a register, then issuing an indirect call to it [or indirect jump if tail call optimizations took effect]. The address space that contains the function open() is in the .text segment of your library, which gets mapped as executable. Since the dynamic linker resolves the address of a function and places that into the GOT, execution takes place as expected. >> And no, you can not make ld.so dereference the pointer as you want it >> to. Otherwise, it would not be able to resolve other symbols of similar >> types as it would be expected to do. > > Hmm... Not quite understand. If would be better if you can provide > some examples. In contrast, your original code says: int (*open)(const char*, int, ...); /* code that initializes open to the address of some_function() */ int some_function(const char* pathname, int flags, ...) { /* stuff */ } Now the symbol open is no longer resolves to a function, but to a variable [of pointer type]. When you issue a call to open() in your application, what gets placed in the GOT is the address of that symbol [the pointer variable, not what the variable is pointing to]. When the indirect jump in the PLT gets executed, the program counter ends up in non-executable memory, so you crash. What I tried to mention above is that you can't have the dynamic linker dereference your pointer [open] in this case, and place the dereferenced address [the address of some_function()] in the GOT. If you do that, you are breaking the way the dynamic linker works. The basic example is when you expect a pointer to actually be resolved, instead of what the pointer is dereferecing. The more complex caveat is that compiled code loses type information. There is no real way for the machine to differentiate the type of open from any other integer value. Cheers, Orlando.
Attachment:
signature.asc
Description: OpenPGP digital signature
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |