RISC-V disassembly doesn't seem to know about multiply instructions

I built llvm + clang from source, a github clone from today:

clang version 11.0.0 (https://github.com/llvm/llvm-project.git 91aa67bf290bc7f877b1b90128284863bc31aa43)

I compiled a small program:

#include <stdint.h>

int main() {
uint8_t a = 2;
uint8_t b = 5;
uint8_t c = a * b;

$ clang -c -target riscv32 -march=rv32imc -g main.c
Works fine.

The dumped assembly seems to not know about the multiply instruction - is that expected? See offset 1e in the listing below. Happily, the opcode value does appear to match the MUL instruction.

$ llvm-objdump -S main.o

For your architecture (rv32imc), you’ll need to pass `-mattr=+m,+c` which allows llvm-objdump to disassemble both the M and the C RISC-V extensions.

For more general background: `-mattr=` takes a comma separated list of features to enable (+feature) or disable (-feature). The RISC-V backend has one “feature” per implemented RISC-V architectural extension, each named using the lower case letter that corresponds to the extension in the RISC-V specification. LLVM chooses a default set of features based on the triple, but for `riscv32` (which expands to `riscv32-unknown-elf`) we enable the features that correspond to `rv32i` only.

I hope this helps you out! It is good to know that this is somewhere the RISC-V backend could improve its documentation.


Hi Sam,

I'm wondering in this case whether for the disassembler we should be
using a different default that explicitly enables all the standard
extensions to match what it looks like GNU binutils objdump is doing (I
note we already do this for extracting compressed support out of the
e_flags field in ElfObjectFile.cpp)?

I know there is the .riscv.attributes section that gas now adds that
stores this information, which we could use at some point to autoenable
the correct feature subset, but it looks like LLVM doesn't yet generate
or support parsing that. Do we know if anyone has been working on or
plans on adding support for that.


Thanks for the explanation. Why not just always enable all of them during objdump? If the binary wasn’t compiled with the M instruction it won’t be present in the machine code right?