Неожиданное поведение "lui a4,% hi (0x0001ff00)" - PullRequest
0 голосов
/ 19 ноября 2018

У меня проблемы с функцией ассемблера %hi(). Этот вопрос специфичен для ассемблера RISC-V GNU. Компиляция этой программы:

lui     a4,%hi(0x0001ff00)     # Does not give what I expect
lui     a4,0x1f                #
.word   0x0001f737             #

с

riscv32-unknown-elf-as  -o strange_lui.o strange_lui.s
riscv32-unknown-elf-objdump -D strange_lui.o 

1008 * дают *

strange_lui.o:     file format elf32-littleriscv
Disassembly of section .text:
00000000 <.text>:
0:  00020737            lui a4,0x20
4:  0001f737            lui a4,0x1f
8:  0001f737            lui a4,0x1f

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

riscv32-unknown-elf-as  -v
GNU assembler version 2.31.1 (riscv32-unknown-elf) using BFD version (GNU Binutils) 2.31.1

Ответы [ 2 ]

0 голосов
/ 05 декабря 2018

В итоге, макрос "% hi ()" принимает значение int со знаком, если используется со значением со знаком, возвращенным функцией "% lo ()".

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

Так что должна быть другая форма, такая как "% hu ()", которая будет использоваться с "% lu ()", чтобы не предполагать это расширение знака нижней части и даже не предполагать, что будет использоваться "% lu ()"

0 голосов
/ 20 ноября 2018

Функция %hi(...) умнее, чем выглядит. Он не просто возвращает верхние 20 бит данного аргумента.

%hi предполагает использование в инструкции lui, за которой вскоре последует другая инструкция, такая как add %lo(...), которая завершит 32-битную загрузку регистра, предоставив младшие 12 бит.

Во время выполнения команды add эти младшие 12 битов будут расширяться знаком для получения 32-битного значения, которое затем добавляется к исходному содержимому регистра. Когда верхний бит младшего 12 равен 0, этот шаг расширения знака не влияет на существующие старшие 20 битов регистра. Однако, когда старший бит младшего 12 равен «1», расширение знака приводит к вычитанию единицы из существующего значения старших 20 битов регистра.

В этом случае функция %hi(0x0001ff00) видит, что крайний левый бит младшего 12 равен «1». Поэтому он ожидает вычитание, которое будет выполнено следующим add %lo(0x0001ff00) и записывает 0x00020 в верхние 20 битов регистра. Это 0x00020 будет преобразовано в желаемое 0001f ожидаемым расширением знака add.

Если вы хотите, чтобы ваша программа генерировала одну и ту же инструкцию для всех трех операторов, задайте %hi аргумент, младшие 12 бит которого имеют 0 в крайнем левом положении. Что-то вроде lui %hi(0x0001f700) сделает это.

...