Смещения переходов и ветвей RISC-V

Меня смущает поведение ассемблера RISC-V (rv64). Обратите внимание, что этот вопрос касается того, как должна вести себя удобочитаемая сборка, а не того, как ведут себя машинные инструкции (это ясно).

Кажется, что beq rs1, rs2, x устанавливает PC ← x, если R[rs1] = R[rs2], а не PC ← PC + x. Это отлично. Однако, похоже, существует несоответствие в том, устанавливает ли j xPC ← x или PC ← PC + x.

Вот последовательность, которая привела к этому вопросу:

Рассмотрим следующую ассемблерную программу:

addi x1, x1, 1
beq x1, x1, bob
addi x2, x2, 3
bob:
addi x3, x3, 4
addi x4, x4, 5

Если собрать, а потом разобрать, то получим:

addi ra,ra,1
beq ra,ra,0xc
addi sp,sp,3
addi gp,gp,4
addi tp,tp,5 # 0x5

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

addi ra,ra,1
bne ra,ra,0xc
j 0x8
addi sp,sp,3
addi gp,gp,4
addi tp,tp,5 # 0x5

Следовательно, похоже, что j 0x8 должно использоваться относительное смещение. Он должен пропустить две инструкции вперед, чтобы добраться до нужной нам строки добавления 4. Если бы здесь использовалась абсолютная адресация, он бы застрял в бесконечном цикле сам с собой.

Я был доволен здесь, пока не посмотрел вот эту программу:

addi x1, x1, 1
j bob
addi x2, x2, 3
bob:
addi x3, x3, 4
addi x4, x4, 5

Если собрать и разобрать это, то получим:

addi ra,ra,1
j 0xc
addi sp,sp,3
addi gp,gp,4
addi tp,tp,5 # 0x5

Если j 0xc действительно использует относительное смещение, как и раньше, то переход к метке bob: пропустит инструкцию, в которой она находится, и просто выполнит addi tp,tp,5.

Это не имеет смысла. И чтобы убедиться, что это не так, я использовал встроенную сборку gcc, поместил значения этих регистров в переменные и распечатал их, и на самом деле инструкция addi x3, x3, 4 действительно выполняется, подразумевая, что j 0xc использует абсолютное смещение, противоречит тому, что мы видели ранее.

Извините, если это много, но может ли кто-нибудь объяснить это очевидное несоответствие? (Практически я понимаю, что ответ: «Просто используйте ярлыки», но мне все равно хотелось бы понять)

Редактировать: Вот результат разборки с адресами .s с beq ra,ra,0xc.

0000000000000000 <.text>:
   0:   00108093            addi    ra,ra,1
   4:   00109463            bne ra,ra,c <.text+0xc>
   8:   0000006f            j   8 <.text+0x8>
   c:   00310113            addi    sp,sp,3
  10:   00418193            addi    gp,gp,4
  14:   00520213            addi    tp,tp,5 # 5 <.text+0x5>

Кажется, несоответствие все еще существует.

Обязательно указывайте адреса инструкций, когда вы просматриваете машинный код/дизассемблирование. Если вы посмотрите только на объектный код, а не на исполняемый код, вы можете упустить из виду, что некоторые перемещения представляют собой проблемы, которых вы не видите.

Erik Eidt 06.08.2024 23:31

Вы не можете «разобрать» файл .s, поскольку он уже собран (текст ascii). Я предполагаю, что ваш последний пример — это дизассемблирование файла .o. Обязательно обратите внимание на перемещения, так как компоновщик применит их к байтам кода как часть связывания.

Chris Dodd 07.08.2024 02:53
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы, кажется, запутались в этой инструкции:

8:   0000006f            j   8 <.text+0x8>

Если вы посмотрите на таблицы декодирования инструкций RISCV, вы увидите, что это значение (0x0000006f) на самом деле является инструкцией JAL (код операции 0b1101111) с назначением X0 (игнорируется) и смещением 0. Итак, если вы действительно выполнили эту инструкцию , это был бы бесконечный цикл, прыгающий сам на себя.

Здесь происходит то, что на самом деле это «частичная» инструкция, в которую компоновщик должен заполнить некоторые биты. Где-то в таблице символов объектного файла или в перемещениях будет ссылка на этот адрес инструкции (.text + 8), которая указывает символ, к которому должна перейти эта ветвь, и тип перемещения относительной ветви. Когда компоновщик связывает этот код, он заполняет старшие биты инструкции смещением этого символа, чтобы создать окончательную инструкцию для запуска.

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

pdeqx 07.08.2024 03:12

Другие вопросы по теме