-4

I want to separate the upper and lower half of a 64 bit integer and put them into two registers.

old_timer
  • 69,149
  • 8
  • 89
  • 168
mangos5
  • 31
  • 5
  • This is a duplicate many times over, but `uint32_t lower = bignum & 0xffffffff, upper = bignum >> 32;` – David C. Rankin Feb 14 '20 at 06:38
  • Does this answer your question? [How to store a 64 bit integer in two 32 bit integers and convert back again](https://stackoverflow.com/questions/2810280/how-to-store-a-64-bit-integer-in-two-32-bit-integers-and-convert-back-again) or [How to combine two 32-bit integers into one 64-bit integer?](https://stackoverflow.com/questions/2768890/how-to-combine-two-32-bit-integers-into-one-64-bit-integer) – David C. Rankin Feb 14 '20 at 06:40
  • I know that you have to shift the bits in C, but I can only shift it in registers in assembly, and the registers can only hold 32 bits, so I am not sure how I can get the lower 32 bits. – mangos5 Feb 14 '20 at 06:55
  • 3
    What assembler/hardware are you using. If you have only 32-bit registers and a 64-bit number - it is already split between two registers. Is this for ARM or x86? See [Storing a 64 bit decimal in two 32 bit registers (ASSEMBLY - NASM](https://stackoverflow.com/questions/47241503/storing-a-64-bit-decimal-in-two-32-bit-registers-assembly-nasm) and [Accessing and Modifying Upper Bits in x86 and x64 Registers](http://dsasmblr.com/accessing-and-modifying-upper-half-of-registers/) – David C. Rankin Feb 14 '20 at 06:57
  • Look at C compiler output for a function that takes a uint64_t arg and returns the high or low half. – Peter Cordes Feb 14 '20 at 07:08
  • Here is Peter's other answer I was looking for [How do I atomically move a 64bit value in x86 ASM?](https://stackoverflow.com/questions/48046591/how-do-i-atomically-move-a-64bit-value-in-x86-asm) – David C. Rankin Feb 14 '20 at 07:15
  • I am using the intel assembly – mangos5 Feb 14 '20 at 17:53

1 Answers1

2

Your question is really not clear. You should at least state whether you are using x86 or x64, and whether the source is in a register or in memory.

From a variable in memory

        ; .u64 --> EDI:ESI
.u64    DQ      0x0123456789ABCDEF
        MOV     ESI, [.u64]
        MOV     EDI, [.u64 + 4]

x64, from a register

        ; RBX --> EDI:ESI
        MOV     ESI, EBX
        MOV     RDI, RBX
        SHR     RDI, 32

x86, from a pair of registers

        ; 64-bit numbers are stored in register pairs, usually EDX:EAX
        ; EDX:EAX --> EDI:ESI
        MOV     EDI, EDX
        MOV     ESI, EAX
W. Chang
  • 494
  • 3
  • 10
  • Your last example is copying EDX:EAX to ESI:EDI not EDI:ESI. (i.e. it swaps high/low halves, like a rotate by 32). – Peter Cordes Feb 15 '20 at 07:24
  • Also note that your x86-64 example doesn't need to `mov esi, ebx`, you can just comment that the low half is available in `ebx`. With BMI2, you can `rorx rdi, rbx, 32` to get the high half into EDI if you don't need it zero-extended to 64-bit either. – Peter Cordes Feb 15 '20 at 07:26
  • @Peter Cordes Thanks for pointing out the careless mistake. I made the correction. For your second comment, it really depends on whether `ESI` will be modified or not. If so, the whole `RBX` will be destroyed. – W. Chang Feb 15 '20 at 07:39
  • 1
    Right, you extract the high half *first*, then you can use EBX for the low half. But yeah, if you need the halves zero-extended, you do need mov. You could `mov esi, ebx` / `shr rbx, 32` to turn RBX into EBX:ESI if you don't need to preserve the original RBX. – Peter Cordes Feb 15 '20 at 07:54