Пара R_MIPS_HI16 / R_MIPS_LO16 в другом регистре - PullRequest
0 голосов
/ 22 марта 2020

Я пытаюсь понять, как перемещения R_MIPS_HI16 и R_MIPS_LO16 работают в мипах.

Я написал немного кода c:

static char buf1[0x100];
static int a = 0;
static int b = 0;

char f(int i, int n)
{
    a++;
    b++;
    return buf1[n];
}

Скомпилируйте с mips-linux-gnu-gcc-8 -o test.o -c -O2 -G 0 -g test.c и запустите objdump: mips-linux-gnu-objdump -d -j .text test.o

Я получаю следующее:

00000030 <f>:
  30:   3c070000    lui a3,0x0
  34:   3c060000    lui a2,0x0
  38:   3c020000    lui v0,0x0
  3c:   8ce50004    lw  a1,4(a3)
  40:   8cc30000    lw  v1,0(a2)
  44:   24420008    addiu   v0,v0,8
  48:   00442021    addu    a0,v0,a0
  4c:   24a50001    addiu   a1,a1,1
  50:   24630001    addiu   v1,v1,1
  54:   80820000    lb  v0,0(a0)
  58:   ace50004    sw  a1,4(a3)
  5c:   03e00008    jr  ra
  60:   acc30000    sw  v1,0(a2)

Теперь я запускаю mips-linux-gnu-readelf -r test.o, чтобы получить таблицу перемещений:

Relocation section '.rel.text' at offset 0x79c contains 12 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00000008  00000405 R_MIPS_HI16       00000000   .bss
00000018  00000406 R_MIPS_LO16       00000000   .bss
00000014  00000405 R_MIPS_HI16       00000000   .bss
0000001c  00000406 R_MIPS_LO16       00000000   .bss
00000030  00000405 R_MIPS_HI16       00000000   .bss
0000003c  00000406 R_MIPS_LO16       00000000   .bss
00000040  00000406 R_MIPS_LO16       00000000   .bss
00000038  00000405 R_MIPS_HI16       00000000   .bss
00000044  00000406 R_MIPS_LO16       00000000   .bss
00000058  00000406 R_MIPS_LO16       00000000   .bss
00000034  00000405 R_MIPS_HI16       00000000   .bss
00000060  00000406 R_MIPS_LO16       00000000   .bss

Теперь, согласно ABI , раздел 4-17, каждое перемещение R_MIPS_HI16 имеет соответствующий R_MIPS_LO16. В случае, если перед ним стоит R_MIPS_LO16 без R_MIPS_HI16, он будет ссылаться на предыдущий R_MIPS_HI16.

Если я понимаю это право, это означает, что перемещения в 38 и 44 являются парными. Это имеет смысл - в адресе 38 мы перемещаем верхнюю часть адреса в регистр (v0), а в 44 мы добавляем в тот же регистр, чтобы завершить загрузку адреса.

Что я не делаю Я понимаю, что перемещение в 58 также связано с тем же R_MIPS_HI16, но в этом адресе мы не обращаемся ни к какому регистру, который использовался в предыдущих командах, и они не кажутся связанными. На самом деле эта команда, похоже, относится к паре 30 и 3 c.

Что здесь происходит?

1 Ответ

0 голосов
/ 22 марта 2020

Вы наблюдаете оптимизацию для a++ и b++.

Хотя можно подумать, что b = b + 1 содержит нагрузку b и хранилище b, требующее * Пара 1008 * для чтения b и пара lui/sw для записи b, компилятор знает, что для чтения b и записи b требуется одинаковое точное значение lui, поэтому он исключает второй lui и повторно использует целевой регистр первого lui - таким образом он делает lui/lw/sw.


Если вы писали это вручную, и у вас была небольшая программа. Вы могли бы использовать / поделиться одним lui для всех глобальных переменных.

Но поскольку эти переменные назначены .bss (все они инициализируются нулями), компоновщик определяет их окончательное расположение (в некоторых системах, хотя они объявлены вместе в исходной программе, они являются отдельными элементами), и поэтому мы не знаем, насколько близко они будут находиться во время компиляции.

Далее, так как это фрагмент программы, мы также не знаем, сколько всего глобалов будет для программы, и, таким образом, между любыми двумя глобалами может возникнуть граница в 64 КБ, то есть для этих двух глобалов потребуется разное lui.

Поскольку окончательные определения сделаны компоновщиком, компилятор принимает здесь наихудший случай и использует отдельный lui для каждой глобальной переменной.


После некоторого обсуждения ...

Я вижу, к чему вы клоните. Я сказал вам, что 30,3 c и 58 связаны с одинаковым доступом к переменным, и это правда. С перемещениями я не знаком, но вы можете найти это уместным:

https://github.com/NationalSecurityAgency/ghidra/issues/909

Хотя я понимаю, как объясняется ABI , HI16 не влияет на исправление перемещения LO16. В нашей текущей реализации только LO16 влияет на исправление HI16 из-за потенциального переноса в верхние 16-битовые значения во время вычисления HI16.

Суть в том, что в то время как HI16 должен быть в паре с LO16 для вычисления переноса, повторение ранее сопряженного LO16 в порядке без предшествующего HI16, потому что соответствующий перенос в HI16 уже выполнен - ​​поэтому перемещения HI16 / LO16 не являются действительно парными 1: 1.

...