3

On ARM in thumb mode, it is possible to build a "jump table" (jump to the n-th pointer) as follows:

    tbb [pc, r1]
    .byte   (foofoo1-.Ltable)/2
    .byte   (foofoo2-.Ltable)/2

This only works if each of the (foofoo1-.Ltable)/2 expressions fits within 0…255. There does not seem to be a safe and simple way to check for this. GNU assembler checks that these bytes fit within -128…255, which is insufficient. clang does not even check.

    .byte   -((foofoo1-.Ltable)/2)*(foofoo1>.Ltable) + (foofoo1<=.Ltable)*100000

works with GNU assembler for checking that the byte is nonnegative (it produces -100000 if it is negative, which triggers the overflow check), but this does not work with clang.

Is there any way to reliably check for the range of an expression involving differences of labels?

I suppose compilers have their own way to check is a label is within a certain number of bytes from another label, or at least safely approximate this decision, but I'd like a double check on this.

David Monniaux
  • 1,948
  • 12
  • 23
  • this is assembly and tagged as such, just write the limits into the code. – old_timer Nov 25 '22 at 18:37
  • labels are just addresses, and to a processor addresses are just bits, and you can do math on bits. – old_timer Nov 25 '22 at 18:37
  • Why use a jump table. Pad the assembler basic blocks to make them a power of two and just use `add pc,pc,RN lsl #sz`? Use '.error' and conditions for this and you just need to check the extremums of the table and add comments for those who modify the code. Ie, you can see that foofoo2 is place regularly after foofoo1, so it will be the extreme value. – artless noise Nov 26 '22 at 15:05
  • .error works inside conditionals, and GNU assembler refuses certain such conditionals on grounds that they depend on future symbols and it's doing only one pass. And, no, padding entire big blocks is not an option. (Your suggestion is otherwise currently implemented as jumping into an array of branches.) – David Monniaux Nov 26 '22 at 19:05

0 Answers0