Почему адрес _GLOBAL_OFFSET_TABLE_ зависит от того, какая функция его принимает? - PullRequest
0 голосов
/ 10 января 2019

Я хотел бы взять и использовать адрес _GLOBAL_OFFSET_TABLE_. Я ожидаю, что адрес этого символа не изменяется в течение программы.

Однако значение его адреса зависит от того, какая функция его принимает:

#include <iostream>
#include <cassert>

extern void* _GLOBAL_OFFSET_TABLE_;

void* foo()
{
  return (void*)&_GLOBAL_OFFSET_TABLE_;
}

void* bar()
{
  return (void*)&_GLOBAL_OFFSET_TABLE_;
}

void* baz()
{
  return (void*)&_GLOBAL_OFFSET_TABLE_;
}

int main()
{
  std::cout << "foo(): " << foo() << std::endl;
  std::cout << "bar(): " << bar() << std::endl;
  std::cout << "baz(): " << baz() << std::endl;

  assert(foo() == bar());
  assert(foo() == baz());
  assert(bar() == baz());

  return 0;
}

Вывод программы:

$ clang global_offset_table_repro.cpp -lstdc++
$ ./a.out 
foo(): 0x20076c
bar(): 0x20075c
baz(): 0x20074c
a.out: global_offset_table_repro.cpp:27: int main(): Assertion `foo() == bar()' failed.
Aborted (core dumped)

Компиляция с -fPIC дает согласованный результат:

$ clang global_offset_table_repro.cpp -lstdc++ -fPIC
jhoberock@jhoberock-dt:~/dev/git/oz$ ./a.out 
foo(): 0x601000
bar(): 0x601000
baz(): 0x601000

Как и при компиляции с g++:

$ g++ global_offset_table_repro.cpp -lstdc++
$ ./a.out 
foo(): 0x555eab725f80
bar(): 0x555eab725f80
baz(): 0x555eab725f80

Детали компилятора:

$ clang --version ; echo ; g++ --version
clang version 4.0.1-6 (tags/RELEASE_401/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

g++ (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Ожидается ли поведение clang?

...