I'm trying to build an assembly source file for Android/MIPSEL32. It's a test case for a weird Pascal compiler issue; but the bug might be in assembler after all.
How does the MIPS assembler implement the j
command in PIC mode? I have a j
-to-label statement, where the label is 184200 bytes away from the current instruction; when assembling in PIC mode, the assembler errors out:
a.s:67: Error: Branch out of range
My trusty MIPS manual says that j
takes an absolute offset, applied within a 256-MB block. The size of the whole code block is much less than 256 MB. I don't see what's wrong with this j
. When not compiling for PIC, it works as expected. And why is talking about a branch? Branch and jump are explicitly distinct on MIPS.
The PC-relative offset would be 18 bits long in this case. Can't help noticing that it's just above the limit for the b
. Would the assembler quietly convert j
to b
in PIC mode? It's not unheard of that an assembler-level command is implemented as a macro with the same name as the underlying architectural command. But there's a set .nomacro
in the function prologue, isn't there?
Please explain, and maybe offer a workaround. I don't mind an additional step of scripted assembly fixup on the build path.
A similar problem is discussed here, here, here.
For the sake of repro steps, the assembly source goes like this:
.section .text.n_main
.balign 4
.globl PASCALMAIN
.type PASCALMAIN,@function
PASCALMAIN:
.globl main
.type main,@function
main:
.ent main
.set nomips16
.frame $sp,112,$ra
.mask 0xC0010000,-40
.fmask 0x00000000,0
.set noreorder
.cpload $t9
.set nomacro
addiu $sp,$sp,-112
sw $ra,72($sp)
sw $fp,68($sp)
addiu $fp,$sp,112
.cprestore 104
sw $s0,64($sp)
lw $t9,%call16(FPC_INITIALIZEUNITS)($gp)
jalr $t9
nop
lw $gp,104($sp)
lw $t9,%call16(fpc_get_input)($gp)
jalr $t9
nop
lw $gp,104($sp)
move $s0,$v0
lw $a1,%got(U_$P$A_$$_S)($gp)
addiu $a1,$a1,%lo(U_$P$A_$$_S)
move $a0,$s0
addiu $a2,$zero,255
lw $t9,%call16(fpc_read_text_shortstr)($gp)
jalr $t9
nop
lw $gp,104($sp)
lw $t9,%call16(FPC_IOCHECK)($gp)
jalr $t9
nop
lw $gp,104($sp)
move $a0,$s0
lw $t9,%call16(fpc_readln_end)($gp)
jalr $t9
nop
lw $gp,104($sp)
lw $t9,%call16(FPC_IOCHECK)($gp)
jalr $t9
nop
lw $gp,104($sp)
lw $v0,%got(U_$P$A_$$_I)($gp)
sw $zero,%lo(U_$P$A_$$_I)($v0)
lw $v0,%got(U_$P$A_$$_S)($gp)
lbu $v0,%lo(U_$P$A_$$_S)($v0)
beq $v0,$zero,.Lj15
nop
# fixup_jmps, A_BA changed into A_J
j .Lj16
nop
.Lj15:
##### Then there's the following fragment, repeated 9210 times:
lw $v0,%got(U_$P$A_$$_I)($gp)
lw $v1,%lo(U_$P$A_$$_I)($v0)
addiu $v1,$v1,1
lw $v0,%got(U_$P$A_$$_I)($gp)
sw $v1,%lo(U_$P$A_$$_I)($v0)
##### End of repeating fragment
.Lj16:
lw $t9,%call16(FPC_DO_EXIT)($gp)
jalr $t9
nop
lw $gp,104($sp)
lw $s0,64($sp)
lw $fp,68($sp)
lw $ra,72($sp)
jr $ra
addiu $sp,$sp,112
.set macro
.set reorder
.end main
The assembler invokation command is:
mipsel-linux-android-as.exe -mabi=32 -march=mips32 -W -EL -KPIC -o a.o a.s
EDIT: the Free Pascal folks have fixed the underlying issue. Now this should not arise, at least not in this particular context.