我正在编译(使用RV32I汇编程序)以下代码 - 在命令行上没有发布错误。
slt x15,x16,x17 # line a
slt x15,x16,22 # line b immediate operand
slti x15,x16,22 # line c
sltu x15,x16,x17 # line d
sltu x15,x16,22 # line e immediate operand
sltiu x15,x16,22 # line f
我注意到为b行生成的机器代码与为c行生成的机器代码相同。我注意到e和f行的情况相同 - 这两行的机器代码是相同的。这台机器输出的这些具体说明,不符合我的期望。汇编程序是否应该抛出错误或警告操作数在技术上对于“slt x15,x16,22”不正确 - 并且应该使用该指令的直接版本 - “slti x15,x16,22”?我使用'-warn'选项调用汇编程序。
这个结果似乎违背了这些指令的2个不同版本的目的。所有操作数都是寄存器的版本,另一个版本具有寄存器和一个立即操作数。如果意图使用'x22'而不是'22'怎么办?
答案 0 :(得分:0)
如评论中所述,我已将此问题移至GitHub,作为riscv / riscv-binutils-gdb上的问题#79。
对我原来问题的简短回答是汇编程序有一个功能可以将SLTU,regX,regY,imm等指令转换为指令的直接版本 - SLTIU regX,regY,imm。我没有看到任何解释此功能的文档。
通过试验,这里是我发现的执行此操作的指令列表。
.text
slt x0,x0,-1 # bug
sltu x0,x0,0 # -> sltiu
add x0,x0,5 # -> addi
xor x0,x0,8 # -> xori
or x0,x0,12 # -> ori
and x0,x0,16 # -> andi
sll x0,x0,6 # -> slli
srl x0,x0,4 # -> srli
sra x0,x0,9 # -> srai
这些说明汇编时没有错误或警告。我用下面的列表文件输出验证了机器代码。 (通过使用x0寄存器简化了此任务)。
Disassembly of section .text:
0000000000000000 <.text>:
0: fff02013 slt x0,x0,-1
4: 00003013 sltiu x0,x0,0
8: 00500013 addi x0,x0,5
c: 00804013 xori x0,x0,8
10: 00c06013 ori x0,x0,12
14: 01007013 andi x0,x0,16
18: 00601013 slli x0,x0,0x6
1c: 00405013 srli x0,x0,0x4
20: 40905013 srai x0,x0,0x9
SLT指令将为SLTI编写机器代码,但列表文件显示SLT - 我认为这是一个错误。有关详细参数,请参阅GitHub#79。所有其他说明都按预期工作。
只有在基本指令中有基指令对时,此方法才有效。像ADD / ADDI或XOR / XOI。但是,SUB在RiscV ISA中没有SUBI指令。当我收到错误尝试使用立即操作数组装SUB时,我确认了这一点。因此,如果您是懒惰的汇编程序员并且您不想使用正确的操作数作为基本指令 - 现在您必须记住除了SUB之外它应该正常工作。或者将SUBI指令添加到自定义RiscV ISA。
以下是一些哲学评论(因此,如果您的RiscV项目明天到期,您可以跳过本答复的其余部分)。首先,我对批评任何开源项目感到内疚。我是很长时间的Linux用户,并且使用过很多开源工具。不仅适用于业余爱好工作,也适用于IBM,HP和Dell使用的产品。我过去曾经使用过6个装配工 - 具有不同的专业水平。从8080/8085开始,我在大学阶段教授汇编语言/计算机架构。我不得不承认,有很多专业知识围绕着RiscV徘徊 - 但不过,我并不认为自己是装配工的总菜鸟。
1)汇编程序应该接近基本指令 - 因此它们应该在偏离时提供非常好的理由。类似这样的功能,其中ADD在汇编程序内部转换为ADDI - 我觉得这个功能提供的价值非常小。 IMO在使用C / C ++中的反汇编时可能会有一些价值 - 但我不能指责它。如果某人有关于为什么采取这种方法的一些细节,请发布。
2) RiscV被吹捧为全新的开放式ISA。但是,它类似于MIPS,问题是MIPS binutils行李附带RiscV。好像我已经直接进入&#34;它在MIPS中工作所以它必须在RiscV&#34;思考GitHub#79。
3)如果您不喜欢汇编助记符 - 或者懒得使用正确的操作数来执行指令 - 那么请考虑编写宏。例如,您可以为SUB操作编写宏来处理立即参数。抵制将宏观思想带入汇编程序的冲动 - 特别是如果新用户不能很好地记录它。我发现的这个功能非常类似于汇编程序中的内置宏。
4)列表文件中的错误很重要 - 对于某些人来说,它们对验证任务至关重要。他们应该认真对待并加以解决。我不确定列表文件的SLT到SLTI的错误是否是汇编程序的错误,这可能是binutils objdump实用程序中的问题。
5) ISA中定义的伪指令 - 就像内置宏一样。我认为应该谨慎使用它们。因为,我认为他们可以增加更多的混乱。我为PUSH和POP等堆栈操作编写宏。我不介意写这些宏 - 我觉得我在汇编程序或ISA中需要很多伪指令。熟悉gcc / gnu样式汇编程序语法的人应该能够仅使用基本指令快速编写一些测试代码,而不必担心在汇编程序中发现技巧。我意外地偶然发现了SLT技巧(错字)。
6)这种在RiscV汇编程序中转换指令的技巧是以强大的打字为代价的。操作数。如果你打错(就像我做的那样) - 但是你打算使用所有寄存器操作数作为基本指令 - 你将获得指令的直接形式而没有发布警告。所以请考虑这是一个友好的单挑。我更喜欢在汇编程序中调用KIS原则,并倾向于严格执行正确的操作数。或者为什么不提供汇编选项来打开/关闭此功能?
7)越来越多的装配工似乎主要用于调试和验证,而不是用于通用软件开发。如果您需要更多抽象代码工具 - 通常会转向嵌入式内核的C或C ++。是的,您可以疯狂编写许多汇编宏,但在C / C ++中编码要容易得多。您可能使用一些内联汇编程序来优化一些时间关键代码 - 当然,它有助于反汇编以查看已编译的C / C ++代码。但是C / C ++编译器已经有了很大的改进,对于许多项目来说,这可以使组件优化过时。程序集用于启动代码 - 例如如果你将Uboot bootloader移植到另一个处理器,你可能需要处理汇编程序中的一些启动文件。所以,我认为汇编程序的目的已经随着时间的推移变成了一些启动文件任务,但在调试和验证方面最有价值。这就是为什么我认为像列表文件这样的东西必须是正确的。具有此功能的命令列表(例如,基于操作数类型从ADD转换为ADDI)意味着汇编程序员只需要掌握一条指令。但是RiscV无论如何都有一小部分基本指令。如果您对旧的CISC处理器有任何经验,这一点很明显。实际上,Risc处理器默认情况下应该有一个小指令集。所以我在原帖中的问题 - 为什么要立即使用该指令?答案是 - 根据我发现的指示 - 你不需要它们。您可以使用所有寄存器或寄存器以及立即值对它们进行编码 - 汇编器将对其进行编制。但是HW实现绝对需要两个版本(仅注册操作数,寄存器和立即操作数)。例如。核心需要从寄存器文件输出或从指令字中剥离的立即值引导ALU输入操作数。
那么,我原来问题的答案 - &#34;为什么会创建完全相同的机器代码?&#34; - 是&#34;因为这就是汇编程序的工作方式&#34;。但就目前而言 - 这个功能大部分时间都有效..