Как мне обратиться к глобальной переменной в динамически связанной библиотеке? - PullRequest
4 голосов
/ 02 мая 2009

Средой является Solaris на 32-битной SPARC, но я думаю, что это более общая проблема с динамическим связыванием и / или позиционно-независимым кодом.

У меня есть программа сборки, которую я компилирую как независимый от позиции код и динамически связываю его с программой на Си. Он работает нормально, за исключением того, что я не могу сослаться на любую память, зарезервированную программой сборки из программы сборки. Прыжки внутри программы сборки работают нормально.

Я просто хочу читать и записывать в память в программе сборки, но всякий раз, когда я пытаюсь это сделать, я получаю ошибку сегментации.

Я написал эту тестовую программу для устранения этой проблемы

  .section ".data"
  .global foo
foo: .word 1
  .section ".text"
  .global testprog
testprog:
  save %sp, -(92+4), %sp
  sethi %hi(foo), %o0 ! set foo, %o0
  or %o0, %lo(foo), %o0 
  call print_int
  nop
  ret
  restore

Я компилирую это с

as -K PIC -b

и добавьте получившийся .so в C

dlhandle = dlopen(obj_file, RTLD_NOW)
dl_testprog = dlsym(dlhandle, "testprog")

когда я звоню dl_testprog(), он печатает "4". Он также печатает «4», если я пытаюсь напечатать адрес testprog или print_int. Переход на метку и все остальное работает просто отлично. Глядя на разборку, foo заменяется на 0x0, как и должно быть.

Должен ли я пройти через _GLOBAL_OFFSET_TABLE_ или что-то еще, чтобы иметь возможность писать в свою память в программе сборки? Если да, то как мне это сделать? Все, что я пробовал, привело к segfault, и я не смог найти очень хорошее руководство, как это сделать (что заставляет меня поверить, что вы не должны этого делать. Разве это не проблема с линкерами?) .

Ответы [ 2 ]

3 голосов
/ 03 мая 2009

Решил это, посмотрев код, который выводит компилятор C для PIC, что я и должен был делать с самого начала вместо чтения руководств и случайных веб-страниц.

Возможно, это было очевидно, но на самом деле реальный адрес объекта в PIC (по крайней мере на 32b SPARC) равен (_GLOBAL_OFFSET_TABLE_ + PC + object). И условием является вычисление адреса GOT для% l7 в начале функции. Подробности здесь , за исключением того, как фактически рассчитать% l7.

addpc:
  add %o7, %l7, %l7 ! %o7 == addr of call == PC
  retl
   nop
testprog:
  sethi %hi(_GLOBAL_OFFSET_TABLE_-8), %l7 ! -8 = distance from call addpc
  add %l7, %lo(_GLOBAL_OFFSET_TABLE_-4), %l7 
  call addpc ! add PC to %l7
   nop
1 голос
/ 02 мая 2009

Да, я считаю, что вы должны пройти через GOT, чтобы обратиться к личным данным. См. Раздел 9.2 здесь . Хотя NASM - это ассемблер x86, общие принципы должны быть такими же и для SPARC / Solaris.

Кроме того, ассемблеры AT & T обычно используют синтаксис '@got' для указания перемещения по отношению к. ПОЛУЧИЛ. Точные подробности будут описаны в вашем руководстве на ассемблере, то есть детали синтаксиса NASM не будут работать с ассемблером Solaris.

...