Why get the wrong results when doing pointer arithmetic in C on dynamically linked characters?

I came across a strange situation where pointer arithmetic was performed involving dynamically related characters leading to incorrect results. I'm not sure if some linker options are simply missing or if this is a linker error. Can someone explain what is wrong in the following example?

Consider the following code ( lib.c ) for a simple shared library:

 #include <inttypes.h> #include <stdio.h> uintptr_t getmask() { return 0xffffffff; } int fn1() { return 42; } void fn2() { uintptr_t mask; uintptr_t p; mask = getmask(); p = (uintptr_t)fn1 & mask; printf("mask: %08x\n", mask); printf("fn1: %p\n", fn1); printf("p: %08x\n", p); } 

This operation is a bitwise AND between the address fn1 and the variable mask . The application ( app.c ) simply calls fn2 as follows:

 extern int fn2(); int main() { fn2(); return 0; } 

This leads to the following conclusion ...

 mask: ffffffff fn1: 0x2aab43c0 p: 000003c0 

... which is clearly wrong, because the same result is expected for fn1 and p . The code runs on the AVR32 architecture and is compiled as follows:

 $ avr32-linux-uclibc-gcc -Os -Wextra -Wall -c -o lib.o lib.c $ avr32-linux-uclibc-gcc -Os -Wextra -Wall -shared -o libfoo.so lib.o $ avr32-linux-uclibc-gcc -Os -Wextra -Wall -o app app.c -L. -lfoo 

The compiler believes that this is the optimal solution for loading the mask variable into 32-bit register 7 and splitting & -operations into two assemblers of operations with direct operands.

 $ avr32-linux-uclibc-objdump -d libfoo.so 000003ce <fn1>: 3ce: 32 ac mov r12,42 3d0: 5e fc retal r12 000003d2 <fn2>: ... 3f0: e4 17 00 00 andh r7,0x0 3f4: e0 17 03 ce andl r7,0x3ce 

I assume that the immediate operands of the and commands do not move to the load address fn1 when the shared library is loaded into the application address space:

  • Is this behavior intentional?
  • How can I find out if there is a problem when linking a shared library or when downloading an executable file?

Reference Information. These are not academic questions. OpenSSL and LibreSSL use similar code, so changing the source of C is not an option. The code runs well on other architectures, and, of course, there is an inappropriate reason for performing bitwise operations on function pointers.

+6
source share
1 answer

after fixing all the "slopiness" in the code, the result:

 #include <inttypes.h> #include <stdio.h> int fn1( void ); void fn2( void ); uintptr_t getmask( void ); int main( void ) { fn2(); return 0; } uintptr_t getmask() { return 0xffffffff; } int fn1() { return 42; } void fn2() { uintptr_t mask; uintptr_t p; mask = getmask(); p = (uintptr_t)fn1 & mask; printf("mask: %08x\n", (unsigned int)mask); printf("fn1: %p\n", fn1); printf("p: %08x\n", (unsigned int)p); } 

and the output (on my 64-bit Linux computer):

 mask: ffffffff fn1: 0x4007c1 p: 004007c1 
0
source

Source: https://habr.com/ru/post/1012622/


All Articles