I have multiple very-tiny questions in assembly which are related too so I collected them in this question instead of opening multiple ones and spamming the forum.
All questions relate to Assembly At&t syntax:
Why I can't write something like:
cmp %eax, $0x2
jg goHere
Why it won't allow doing that compare operation (result isn't saved in one of the operands so it doesn't make sense not to allow it...) Note: I know I can solve this by reversing order and do jl
instead of jg
.
In att syntax this is supposed to check if 0x2 is bigger than %eax.
Why I can write:
mov $41, %rax
While I can't write:
mov ($41), %rax
That's quite strange, I was told by someone using of braces doesn't matter in assembly.
When saving a string in memory, let's say "ABC" in address 0x100 how the memory should look like:
0x100 - A 0x101 - B 0x102 - C
0x100 - C 0x101 - B 0x102 - A
For 1, I have no special knowledge about the original design of x86, but I suspect that the reason we don't have cmp %reg, $imm
is because of the relationship between cmp
and sub
. The instruction cmp $imm, %reg
behaves exactly like sub $imm, %reg
, with the one exception that for cmp
the result of the subtraction is not written to the destination %reg
, but instead is discarded. But the result of the subtraction is still computed internally by the CPU and used to set the flags. (At least this is true conceptually, and early CPUs almost certainly did the full subtraction; modern CPUs might have some optimizations that I don't know about.)
So this means that cmp
could be implemented nearly for free once you had sub
. You could use almost exactly the same circuitry and/or microcode. But you still have to decode the instruction, and so they made this easy as well by giving cmp
almost the same encodings as sub
, differing only in one bit. For instance, sub %reg, %reg/mem
is opcodes 28h/29h and cmp %reg, %reg/mem
is opcodes 38h/39h, differing only in bit 4. That one bit just signals the CPU whether to write the result to the destination operand or discard it.
This made it natural to give cmp
exactly the same forms as sub
:
We have sub %reg, %reg
so there is cmp %reg, %reg
.
We have sub %reg, mem
so there is cmp %reg, mem
.
We have sub mem, %reg
so there is cmp mem, %reg
.
We have sub $imm, %reg
so there is cmp $imm, %reg
.
There is even a special short encoding of sub $imm, %al/%ax/%eax/%rax
which has a parallel cmp $imm, %al/%ax/%eax/%rax
.
But there is no encoding of sub %reg, $imm
because that would be nonsense, so cmp %reg, $imm
would have needed a new encoding that wouldn't be parallel to an existing one for sub
. The designers presumably decided not to waste decoding transistors and opcode space on creating one, because after all it wouldn't really provide any new functionality: cmp
is practically always used in conjunction with a conditional jump (or later, conditional set), and in that case you can always achieve the same thing by using cmp $imm, %reg
and reversing the test in the subsequent conditional jump/set.