cltd
converts signed long to signed double long
If you want to see a diagram of what happens, jump to page 160 of http://download.intel.com/products/processor/manual/325462.pdf (more details on page 681)
Question
I found the assembly instruction
cltd
by disassembling code on an Intel architecture. The description I found was, that it clears the %edx register, but I don't understand what happens.... can anyone explain what the command exactly does?
Solution 2
cltd
converts signed long to signed double long
If you want to see a diagram of what happens, jump to page 160 of http://download.intel.com/products/processor/manual/325462.pdf (more details on page 681)
OTHER TIPS
cltd
is an alias for cdq
(reference), which sign-extends eax
into edx:eax
.
What this means in practice is that edx
is filled with the most significant bit of eax
(the sign bit). For example, if eax
is 0x7F000000
edx
would become 0x00000000
after cdq
. And if eax
is 0x80000000
edx
would become 0xFFFFFFFF
.
It looks pretty straightforward to me: cltd converts the signed long in EAX to a signed double long in EDX:EAX by extending the most-significant bit (sign bit) of EAX into all bits of EDX."
Simpler than that, for example:
If the bit is less than 0x7F000000
, which is less than 127 in decimal, its "positive", is between 0 to 127.
If the bit is greater than 0x80000000
it's more than 128 in decimal, its "negative", is between -1 and -128.
So edx will get 0x00000000
for pos and 0xffffffff
for neg.
For example as a hack it can be used to null edx when you know eax is pos number instead of xor rex, edx
.
P.S. cltd
might not compile as 0x99
in some asm compilers. Better to use cdq
Summary of the documentation that was mentioned by Michael:
Intel AT&T From To
CBW CBTW AL AX
CWDE CWTL AX EAX
CWD CWTD AX DX:AX
CDQ CLTD EAX EDX:EAX
CDQE CLTQ EAX RAX
CQO CQTO RAX RDX:RAX
And now some commented code snippets:
/* Quad to Octo: top bit is zero: extend with zeroes. */
mov $0x7FFFFFFFFFFFFFFF, %rax
mov $0x123456789ABCDEF0, %rdx
cqto
mov %rax, %r12
mov %rdx, %r13
/* rax is unchanged. */
LKMC_ASSERT_EQ(%r12, $0x7FFFFFFFFFFFFFFF)
/* rdx is filled with zeros. */
LKMC_ASSERT_EQ(%r13, $0)
/* Quad to Octo: top bit is one: extend with ones. */
mov $0x8000000000000000, %rax
mov $0x123456789ABCDEF0, %rdx
cqto
mov %rax, %r12
mov %rdx, %r13
LKMC_ASSERT_EQ(%r12, $0x8000000000000000)
LKMC_ASSERT_EQ(%r13, $0xFFFFFFFFFFFFFFFF)
/* Intel equivalent syntax also accepte by GNU GAS. */
mov $0x7FFFFFFFFFFFFFFF, %rax
mov $0x123456789ABCDEF0, %rdx
cqo
mov %rax, %r12
mov %rdx, %r13
LKMC_ASSERT_EQ(%r12, $0x7FFFFFFFFFFFFFFF)
LKMC_ASSERT_EQ(%r13, $0)
/* Smaller size example: Double to Quad.
* Also zeroes top 32-bits of RDX like many 32 to 64 operaions. */
mov $0xFFFFFFFF7FFFFFFF, %rax
mov $0x123456789ABCDEF0, %rdx
cltd
mov %rax, %r12
mov %rdx, %r13
LKMC_ASSERT_EQ(%r12, $0xFFFFFFFF7FFFFFFF)
LKMC_ASSERT_EQ(%r13, $0)
/* Even smaller size example: Word to Doubleword.
* Unlike the 32-bit one, does not zero out the top 32-bits of RDX. */
mov $0xFFFFFFFFFFFF7FFF, %rax
mov $0x123456789ABCDEF0, %rdx
cwtd
mov %rax, %r12
mov %rdx, %r13
LKMC_ASSERT_EQ(%r12, $0xFFFFFFFFFFFF7FFF)
LKMC_ASSERT_EQ(%r13, $0x123456789ABC0000)
and
/* CLTQ: top bit is zero: extend with zeroes. */
mov $0x123456787FFFFFFF, %rax
cltq
LKMC_ASSERT_EQ(%rax, $0x000000007FFFFFFF)
/* CLTQ: top bit is one: extend with ones. */
mov $0x1234567880000000, %rax
cltq
LKMC_ASSERT_EQ(%rax, $0xFFFFFFFF80000000)
/* CWTL: zeroes top 32-bits. */
mov $0x123456789ABC8EF0, %rax
cwtl
LKMC_ASSERT_EQ(%rax, $0xFFFF8EF0)
CWTL
/* CBTW. */
mov $0x123456789ABCDE80, %rax
cbtw
LKMC_ASSERT_EQ(%rax, $0x123456789ABCFF80)
CWTL
Runnable GitHub upstreams: