A little question about function address with no-pie on RISCV

ywgrit wangxin03@loongson.cn
Wed Nov 27 10:00:49 GMT 2024


1) The program tested on both riscv and x86_64.

// foo.c

void foo() {}


// main.c

#include <stdio.h>
void foo();

int main() {
         foo();
         printf("%p\n", foo);
         return 0;
}



2) The commands executed.

gcc -fpic -shared -g -o libfoo.so foo.c

gcc -c main.c -o main.o

gcc main.o -o main -lfoo -L. -no-pie





3) The result.

// riscv

./main

0x120000530


// x86_64

./main

0x7ffff3ea05a0



4) The question

With no-pie, riscv print the address of foo@plt which is in main, x86_64 
print the address of foo which is in libfoo.so.

I read the related code of gnu ld, and I find the difference between 
x86_64 and riscv.

// x86_64

if (!local_undefweak
       && !h->def_regular
       && (h->plt.offset != (bfd_vma) -1
           || eh->plt_got.offset != (bfd_vma) -1))
     {
       /* Mark the symbol as undefined, rather than as defined in
          the .plt section.  Leave the value if there were any
          relocations where pointer equality matters (this is a clue
          for the dynamic linker, to make function pointer
          comparisons work between an application and shared
          library), otherwise set it to zero.  If a function is only
          called from a binary, there is no need to slow down
          shared libraries because of that.  */
       sym->st_shndx = SHN_UNDEF;
       if (!h->pointer_equality_needed)
         sym->st_value = 0;
     }

// riscv

if (!h->def_regular)
         {
           /* Mark the symbol as undefined, rather than as defined in
              the .plt section.  Leave the value alone.  */
           sym->st_shndx = SHN_UNDEF;
           /* If the symbol is weak, we do need to clear the value.
              Otherwise, the PLT entry would provide a definition for
              the symbol even if the symbol wasn't defined anywhere,
              and so the symbol would never be NULL.  */
           if (!h->ref_regular_nonweak)
             sym->st_value = 0;
         }

sym(foo@plt)->st_value is set zero on x86_64 but not be set on riscv. So 
when dynamic linker lookup the 'foo', 'foo' was found in main on riscv, 
but not found on x86_64.

I'm not quite sure why these two judgment conditions are not same. And I 
really don't understand about the variable pointer_equality_needed.




More information about the Binutils mailing list