ps2toolchain icon indicating copy to clipboard operation
ps2toolchain copied to clipboard

Assembler - Instructions div/divu expand into macros without means of disabling them

Open Souzooka opened this issue 5 years ago • 4 comments

When compiling assembly .s files which contain division instructions (div/divu), these instructions expand into multiple instructions which check if the divisor is 0, or (for div) if the divisor is -1 and the dividend is INT_MIN.

There seems to be no means of disabling this macro if unwanted, however. Command line arguments -mno-check-zero-division, --no-break, --no-trap, appear to have no effect on the compiled output.

Souzooka avatar May 03 '20 18:05 Souzooka

I'll need a little more information to be able to help and reproduce the issue. Can you provide:

  • example code (few lines)
  • commands used to compile
  • commands used to decompile
  • expected result
  • received result

Hints:

  • Are you using .S or .s ?
  • Are you using gcc or as ?

rickgaiser avatar May 05 '20 12:05 rickgaiser

I am using .s files and using ee-gcc to assemble. The issue can be replicated with an input file containing text such as

  .text
  .global main
  .set noreorder
  .set noat
main:
  div $v0, $v0
  jr $ra
  nop

When assembled with

ee-gcc input.s -mno-check-zero-division

I expect the main subroutine to compile into

main:
  div $v0, $v0
  jr $ra
  nop

While the actual result is:

main:
  bnez $v0, L1
  div $v0, $v0
  break 7
L1:
  dli $at, -1
  bne $v0, $at, L2
  lui $at, 0x8000
  bne $v0, $at, L2
  nop
  break 6
L2:
  mflo $v0
  jr $ra
  nop

Souzooka avatar May 05 '20 13:05 Souzooka

The behaviour is strage, but there's a solution. The ps2's DIV instruction has only 2 operands and places the result in the HI/LO register. However, binutils will always want to see 3 operands, so we have to use $0 as the third operand. You'll have to get the result out of the LO register with mflo $2.

So:

main:
  div $0, $v0, $v0
  mflo $2
  jr $ra

Should work. Don't add the NOP so binutils can optimize the branch delay slot, so the end result woll look like:

main:
  div $0, $v0, $v0
  jr $ra
  mflo $2

rickgaiser avatar May 05 '20 14:05 rickgaiser

That does work as a workaround to the issue, thank you. Certainly a lot easier than writing it out using a .byte directive.

I think it's also worth nothing that this behavior does not apply to div1 and divu1; checking division arguments and mflo only occurs for div/divu.

Souzooka avatar May 05 '20 14:05 Souzooka