Specifying 8 bits directly on x86-64 (GNU Assembler)

I'm trying to write a custom assembly routine, for x86-64 (even an x86 example is good). Problem: My immediate parties are only resolved during communication.

For example,

addq $ Label2-Label1,% rax

will add the difference between the two labels / characters in rax. Unfortunately, since GNU Assembler only does one pass (I don't know why even open source assemblers like FASM do multiple passes), it cannot resolve them, so it will make the linker.

Unfortunately, it will reserve 4 bytes (32-bit immediate) for the linker, which I don't want because the difference in labels is always in the -128 to +127 range.

My question is, how do I force or indicate that the instruction should have an 8-bit key? For example, what's the syntax here? Everything is fine in AT&T or Intel syntax. For example, in NASM, you do:

add rax, byte Label2-Label1

to indicate 8 bits at once. But how to do this in GAZ? What syntax would make it use 8-bit immediate, even if it doesn't know the most immediate ... I'd ideally like this in GAS for some reason, so please don't tell me to use NASM as an answer!

EDIT: Sorry, I forgot to mention that yes it is a "direct link" here. Both of these labels are defined after the instruction, so GAS cannot resolve them, I thought it was a move, but yes, using ".byte label2-label1" works exactly as I tested it, so I know it should be possible if it had some syntax for it ...

+3


source to share


2 answers


If Label1

u Label2

are in the same source file, the issue is not linked to the linker (in which case GAS does not generate any relocations), and it is not because GAS is a one-pass assembler. It's smart enough to generate the correct size branches, which is a similar problem.

The problem comes down to the fact that GAS is not smart enough to select the correct instruction in cases other than hops and branches, and not be able to explicitly specify the size of the operand. The move suffix ".d8" is pretty much the syntax you want, but you are not technically using move. But that won't work, as it leal.d8 Label2-Label1(%eax),%eax

doesn't work, even though the offset is actually being used.

So this leaves only one alternative, manually collecting the opcode. For example, in a 32-bit assembly:



.byte 0x83, 0xC0, (label2 - label1)

      

As to why GAS is only a one-pass assembler and in general it does not execute a number of other assemblers, the answer is simple. It is primarily intended for building GCC output.

+2


source


Unfortunately this is not possible; because GAS doesn't understand what the difference is, it has no choice but to leave a 4 byte entry for the linker to decide. This is because the object file format (which is more than likely ELF) does not support 8-bit permutations - it only supports 32-bit permutations. So it will always use 32-bit immediate.



+1


source







All Articles