Заставить GNU AS использовать альтернативу - PullRequest
0 голосов
/ 29 апреля 2018

У меня есть двоичный файл ARM и немного ассемблерного кода. Разборка из двоичного файла читает

1e40 -> subs r0,r0,#1

Инструкции из кода сборки читаются так же. (Код использует директиву .syntax unified)

Однако, когда я использую GNU AS (из набора инструментов gcc из ARM 2017 Q4), оценивается

subs r0,r0,#1 до

3801-> subs r0,#1

с использованием objdump

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

Ответы [ 2 ]

0 голосов
/ 29 апреля 2018

Просто попробуйте ...

so.s

.thumb
sub r0,#1
.syntax unified
subs r0,r0,#1
sub r0,#1
subs.n r0,#1

собрать и разобрать

arm-none-eabi-as so.s -o so.o
arm-none-eabi-objdump -D so.o

so.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <.text>:
   0:   3801        subs    r0, #1
   2:   3801        subs    r0, #1
   4:   f1a0 0001   sub.w   r0, r0, #1
   8:   3801        subs    r0, #1

РЕДАКТИРОВАТЬ комментарий Олафа.

.thumb
sub r0,#1
sub r0,r0,#1
sub r1,r2,#1
.syntax unified
subs r0,r0,#1
sub r0,#1
subs.n r0,#1
subs.n r0,r0,#1
subs r1,r2,#1


00000000 <.text>:
   0:   3801        subs    r0, #1
   2:   3801        subs    r0, #1
   4:   1e51        subs    r1, r2, #1
   6:   3801        subs    r0, #1
   8:   f1a0 0001   sub.w   r0, r0, #1
   c:   3801        subs    r0, #1
   e:   3801        subs    r0, #1
  10:   1e51        subs    r1, r2, #1

Я / вы / мы должны были бы покопаться в источнике ассемблера, чтобы посмотреть, есть ли способ обойти это. Фуз может иметь самый простой ответ. Вероятно, что ассемблер оптимизирован для того, чтобы с большей гибкостью сразу. Вы, безусловно, можете удалить эту оптимизацию / функцию (если флаг отсутствует).

EDIT2

Возможно, это так.

#define T_OPCODE_SUB_I8 0x3800
#define T_OPCODE_SUB_I3 0x1e00

    else if (rs == rd)
      {
        if (value & ~0xff)
          as_bad_where (fixP->fx_file, fixP->fx_line,
                _("immediate value out of range"));
        newval = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
        newval |= (rd << 8) | value;
      }
    else
      {
        if (value & ~0x7)
          as_bad_where (fixP->fx_file, fixP->fx_line,
                _("immediate value out of range"));
        newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
        newval |= rd | (rs << 3) | (value << 6);
      }

Если вы добавите это

else if (value & ~0x7)
  {
    newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
    newval |= rd | (rs << 3) | (value << 6);
  }

перед

else if (rs == rd)

тогда

.cpu cortex-m7
.thumb
sub r0,r0,#15
sub r0,r0,#1
.syntax unified
subs.n r0,r0,#1
subs.n r0,r0,#15

дает желаемый результат.

   0:   1fc0        subs    r0, r0, #7
   2:   3801        subs    r0, #1
   4:   3801        subs    r0, #1
   6:   1fc0        subs    r0, r0, #7

Так что я думаю, что rs == rd мешает вам генерировать требуемую инструкцию.

РЕДАКТИРОВАТЬ 3

binutils 2.7 не имеет этого определения T_OPCODE_SUB_I8, поэтому, возможно, не имеет поддержки большого пальца, не копал глубже, чем это. binutils 2.8 делает и включает эту оптимизацию. Так что еще в 1997 году это было там. Если вы хотите сгенерировать соответствующую инструкцию с помощью ассемблера gnu, похоже, вам нужно изменить ассемблер gnu ...

0 голосов
/ 29 апреля 2018

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

Обратитесь к «Справочному руководству по архитектуре прикладного уровня ARMv7-M», код операции может быть легко декодирован. Попробуйте, это хорошая практика и всегда хорошая идея держать ее рядом при написании кода машинного уровня.

На самом деле это две разные инструкции, но с одинаковым эффектом.

Первый код операции относится к операции с двумя регистрами (источник, назначение) с небольшим непосредственным 3-битным (расширенный ноль, диапазон 0… 7). Здесь оба регистра оказываются одним и тем же регистром, что фактически делает его уменьшением одного регистра.

Второе - вычитание из одного регистра с 8-битным непосредственным операндом (расширенный ноль, диапазон 0… 255). Непонятно, почему вы получаете два разных варианта, но они не должны иметь никакого значения (по крайней мере, для Cortex-M4 оба занимают один такт, и я был бы удивлен, если бы другие архитектуры имели разные значения).

Таким образом, разборка отражает действующую инструкцию. Кажется, что gas преобразует исходную инструкцию из двух регистров в код операции из одного регистра.

Обратите внимание, что существуют различные операции, которые могут привести к различным кодам операций. Для предоставленной информации не ясно, почему они были выбраны. Imo, второе более разумно, первое имеет смысл, только если задействованы два разных регистра.

Если с вашим кодом возникли проблемы, то, скорее всего, именно эта инструкция. Может быть, пришло время запустить отладчик.

...