- Let's take a look at the assembly instructions.
24:bitwise_16bit_color.cpp **** uint32_t hex = 0;
565 .loc 6 24 0
566 00cf C745C400 movl $0, -60(%rbp)
566 000000
25:bitwise_16bit_color.cpp ****
26:bitwise_16bit_color.cpp **** // set red value from bit 0 ~ 4
27:bitwise_16bit_color.cpp **** hex |= (r & 0x1F);
567 .loc 6 27 0
568 00d6 8B45B8 movl -72(%rbp), %eax
569 00d9 83E01F andl $31, %eax
570 00dc 0945C4 orl %eax, -60(%rbp)
28:bitwise_16bit_color.cpp ****
29:bitwise_16bit_color.cpp **** // set green value from bit 5 ~ 10
30:bitwise_16bit_color.cpp **** hex |= ((g & 0x3F) << 5);
571 .loc 6 30 0
572 00df 8B45BC movl -68(%rbp), %eax
573 00e2 C1E005 sall $5, %eax
574 00e5 25E00700 andl $2016, %eax
574 00
575 00ea 0945C4 orl %eax, -60(%rbp)
31:bitwise_16bit_color.cpp ****
32:bitwise_16bit_color.cpp **** // set blue value from bit 11 ~ 15
33:bitwise_16bit_color.cpp **** hex |= ((b & 0x1F) << 11);
576 .loc 6 33 0
577 00ed 8B45C0 movl -64(%rbp), %eax
578 00f0 C1E00B sall $11, %eax
579 00f3 0FB7C0 movzwl %ax, %eax
580 00f6 0945C4 orl %eax, -60(%rbp)
- It seems that the compiler used following instructions to implement.
instruction |
opcode |
expected behavior |
example |
movl |
C7 |
set a value to a memory location (32bit) |
movl $0, -60(%rbp) |
movl |
8B |
copy a value at a memory location to another (32bit) |
movl -72(%rbp), %eax |
andl |
83 |
bitwise and operation to a memory location (32bit) |
andl $31, %eax |
orl |
09 |
bitwise or operation to a memory location (32bit) |
orl %eax, -60(%rbp) |
sall |
C1 |
bitwise left shift to a memory location (32bit) |
sall $5, %eax |
movzwl |
0F |
expand 16 bit value to longer unsigned integer |
movzwl %ax, %eax |
- It also seems that the result of the operation remains at the latter of the two operands.
- Let's take a look at how to designate operands: values or memory locations.
operand |
designation |
example |
direct value |
decimal number |
$0 , $31 |
eax register |
general purpose register eax (32bit) |
%eax |
ax register |
general purpose register ax (16bit) |
%ax |
pointer |
memory at address |
-60(%rbp) , -72(%rbp) |
rbp register |
base pointer register (64bit) |
%rbp |
- Now let's look at the first a few lines of the assembly code above.
24:bitwise_16bit_color.cpp **** uint32_t hex = 0;
565 .loc 6 24 0
566 00cf C745C400000000 movl $0, -60(%rbp)
- The last line is the machine code / assembly translation from the C/C++ code of the first line.
machine language code |
meaning |
00cf |
the start location of this machine code |
C7 |
movl immediate value |
45 |
(%rbp) addressing using base pointer |
C4 |
offset from %rbp $$ 60_{10}=00111100_2 \ 11000100_2 = C4_{16} $$ |
0000 0000 |
immediate value to write to -60(%rbp) location |
- This line would initialize
uint_32t
variable hex
with zero.
- Now let's take a look at the next a few lines
25:bitwise_16bit_color.cpp ****
26:bitwise_16bit_color.cpp **** // set red value from bit 0 ~ 4
27:bitwise_16bit_color.cpp **** hex |= (r & 0x1F);
567 .loc 6 27 0
568 00d6 8B45B8 movl -72(%rbp), %eax
569 00d9 83E01F andl $31, %eax
570 00dc 0945C4 orl %eax, -60(%rbp)
- The C/C++ line here tries to copy the lower 5 bits of variable
r
to hex
.
- The first assembly instruction copies a 32 bit value to
eax
register.
- The second instruction applies 32bit bitwise and operation to
eax
register. As $31_{10} = 11111_2$, all bits between 31 ~ 5 would be 0.
- The third instruction carrys out bitwise or operation to
uint32_t
variable hex
with the value of eax
register.
- THe following lines are similar, too.
28:bitwise_16bit_color.cpp ****
29:bitwise_16bit_color.cpp **** // set green value from bit 5 ~ 10
30:bitwise_16bit_color.cpp **** hex |= ((g & 0x3F) << 5);
571 .loc 6 30 0
572 00df 8B45BC movl -68(%rbp), %eax
573 00e2 C1E005 sall $5, %eax
574 00e5 25E0070000 andl $2016, %eax
575 00ea 0945C4 orl %eax, -60(%rbp)
- Let's focus on the following two lines.
573 00e2 C1E005 sall $5, %eax
574 00e5 25E0070000 andl $2016, %eax
- Here,
sall $5, %eax
intend to shift the 32bit content of eax
to the left by five binary digits.
- In the third line is as follows.
andl $2016, %eax
- Because
$2016_{10} = 07e0_{16}= 0000 0111 1110 0000_2$
this would turn off bits of eax
except 6 bits associated with g
.
- Compare with C/C++ line. Is the order same? Why or why not?