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?

Was it helpful?

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.

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:

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top