RISC-V assembly features two mnemonics jump and tail, both of which perform an unconditional jump to another symbol. What is the difference between the two?
Both are pseudo-instructions that get expanded by the assembler but the difference is unclear.
It seems that the GNU assembler understands tail XXX as
auipc x6, (something appropriate for XXX)
jr x6, (something appropriate for XXX)
whereas jump XXX, RR is understood as
auipc RR, (something appropriate for XXX)
jr RR, (something appropriate for XXX)
In short, jump lets you choose the temporary register that gets clobbered by the computation of the destination.
In any case, the GNU linker removes the auipc if the target is close enough.
Related
Summary: What is the definitive reference or reference implementation for the RISC-V user-level ISA?
Context: The RISC-V website has "The RISC-V Instruction Set Manual" which explains the user-level instructions very well, but does not give an exact specification for them. I am trying to build a user-level ISA simulator now and intend to write an FPGA implementation later, so the exact behavior is important to me.
A reference implementation would be sufficient, but should preferably be as simple as possible -- i.e. I would try to understand a pipelined implementation only as a last resort. What is important is to have an understanding of the specified ISA and not of a single CPU implementation or compiler implementation.
One example to show my problem is the AUIPC instruction: The prose explanation says that "AUIPC forms a 32-bit offset from the 20-bit U-immediate, filling in the lowest 12 bits with zeros, adds this offset to the pc, then places the result in register rd." I wanted to know whether this refers to the old or new PC, i.e. the position of the AUIPC instruction or the next instruction. I looked at the "RISCV Angel" implementation, but that seems to mask out the lower bits of the (old) PC -- not just of the immediate -- which I could not find any reason for in the spec, not even in the change history of the spec (since Angel is a bit older). Instead of an answer, I now have two questions about AUIPC. Many other instructions pose similar problems to me.
AFAICT the RISC-V Instruction Set Manual you cite is the closest thing there is to a definitive reference. If there are things that are unclear or incorrect in there then you could open issues at the Github site where that document is maintained: https://github.com/riscv/riscv-isa-manual
As far as AIUPC is concerned, the answer is implied, but not stated explicitly, by this sentence at the bottom of page 9 in the current manual:
There is one additional user-visible register: the program counter pc holds the address of the current instruction.
Based on that statement I would expect that the pc value that is seen and manipulated by the AIUPC instruction is the address of the AIUPC instruction itself.
This interpretation is supported by the discussion of the JALR instruction:
The indirect jump instruction JALR (jump and link register) uses the I-type encoding. The target address is obtained by adding the 12-bit signed I-immediate to the register rs1, then setting the least-signicant bit of the result to zero. The address of the instruction following the jump (pc+4) is written to register rd.
Given that the address of the following instruction is expressed as pc+4, it seems clear that the pc value visible during the execution of JALR is the address of the JALR instruction itself.
The latest draft of the manual (at https://github.com/riscv/riscv-isa-manual/releases/download/draft-20190321-ba17106/riscv-spec.pdf) makes the situation slightly clearer. In place of this in the current manual:
AUIPC appends 12 low-order zero bits to the 20-bit U-immediate, sign-extends the result to 64 bits, then adds it to the pc and places the result in register rd.
the latest draft says:
AUIPC forms a 32-bit offset from the 20-bit U-immediate, filling in the lowest 12 bits with zeros, adds this offset to the pc of the AUIPC instruction, then places the result in register rd.
lea 0x1c(%ebp),%eax
So, I understand vaguely what the lea instruction does, and I know those are registers, but what is this structure: 0x1c(%ebp)? I got this code out of objdump.
It is one of the many x86 addressing modes. Specifically, this is referred to as "displacement" addressing.
Since you said you used objdump and didn't specify that you used the -M flag, I'm going to assume this in the GAS syntax (as opposed to Intel syntax). This means that the first operand is the source, and the second operand is the destination.
The lea 0x1C(%ebp),%eax instruction means, "Take the value in %ebp, add 0x1C (28 in decimal), then store that value in %eax".
I am writing a little disassembler using riscv-spec-v2.0 and have some questions about the following instructions and how to correctly disassemble them:
1.
FENCE instruction has "pred" and "succ" bit fields in imm
2.
AMO instructions have "aq" and "rl" bits in in funct7
3.
Float instructions have a "rm" bit field in funct3
All of these bit fields seem to lack mappings in the assembler.
E.g. page 50 just says "FENCE" but not what to do with the intermediate.
Or page 33 has an example of putting .aq or .rl at the end but not what to do if both are present.
4.
SCALL, SBREAK are the same as ECALL, EBREAK
but there is also ERET: so why not drop SCALL and SBREAK
and just use ECALL, EBREAK and ERET because other wise it
is hard to disassemble these opcodes.
The current RISC-V assembler is terse for common defaults:
"FENCE" with no arguments is treated as a full fence (all bits set)
OK to have both on same instruction
Rounding mode not shown if not specified
ECALL and EBREAK will be the new standard names (will be clarified in the revised user ISA manual)
I'm reading about PIC implementation on MIPS on Linux here. It says:
The global pointer which is stored in the $gp register (aka $28) is a callee saved register.
The Wikipedia article about MIPS says the same.
However, according to them, when a .cpload directive is being used in function prologue, it clobbers the previous value of $gp without saving it first. When a .cprestore is used, it saves the current $gp to the stack frame, as opposed to the value of $gp that was there on function entrance. Same goes for the effect .cprestore has on jal/jalr: it restores $gp once the callee returns - assuming the callee might've clobbered it.
And finally, there's nothing in the function epilogue about $gp.
All in all, doesn't sound like a callee-saved register to me. Sounds like a caller-saved register. What am I misunderstanding here?
Linux programs on MIPS can be compiled as pic or not. If compiled as pic, then they must use "abicalls", and its behaviour is a little different from that of the no-abicalls convention.
From the "section Position-Independent Function Prologue" of the "SYSTEM V APPLICATION BINARY INTERFACE - MIPS Processor Supplement 3rd Edition" we can cite:
After calculating the gp, a function allocates the local stack space and saves the gp on the stack, so it can be restored after subsequent function calls. In other words, the gp is a caller saved register.
The code in the following figure illustrates a position-independent function prologue. _gp_disp represents the offset between the beginning of the function and the global offset table.
name:
la gp, _gp_disp
addu gp, gp, t9
addiu sp, sp, –64
sw gp, 32(sp)
So in summary, if you're using -mabicalls then gp is calculated at the beginning of all the functions needing global symbols (with some exceptions), and additionally any code (abi or not) that calls abi code will ensure that the called function address is stored in t9.
can anyone explain what the * in the gnu assembler does? Example:
jmp *0x804a004
This is an entry in a procedure linkage table (plt), maybe someone can clarify what this instruction does and what the * stands for.
I think the "*" means that the address to call or jmp is absolute. If you don't specify it, "as" will assume that the operand is relative to the program counter (PC relative addressing).