简体   繁体   中英

Generate a random 32-bit number to store in a 64-bit register

I want to generate a random 32-bit number. I am using rdrand for this. However, I am having some problems. Since the number can be no more than 32 bits large, I am doing rdrand eax . Here is where the problem arises:

  • I need to be able to refer to this 32-bit number in a 64-bit register since the rest of my codebase uses 64-bit registers. I figured that I could clear rax with a xor to itself, and then only load half of it with rdrand eax . Then I could look at rax , have one half be at most a 32-bit number, and the other half be cleared.

  • When I compare rax with the maximum 32-bit number size, 2147483647 , I get very inconsistent results. Half of the time, the exit code is 1, meaning that the number in rax is, in fact, smaller than 32-bits. But the other half of the time I get 0. It's almost like the result in eax is not always less than or equal to 2147483647 , which is unexpected given what this documentation says.

Does anyone know what is going wrong in my thought process? I am very curious to know. (Note: I'm assembling with Clang on macOS.)

    .global _main
    .text

# how to generate a 32-bit random number that is in rax?
_main:
    xor rax, rax  # clear the top half of the eax-rax register pair
    rdrand eax  # a 32-bit number in rax

    cmp rax, 2147483647
    jle smaller_than_32  # rax <= MAX_32_BIT
    xor rdi, rdi
    jmp end
    smaller_than_32:
        mov rdi, 1
    end:
        mov rax, 0x2000001
        syscall

2147483647 , or equivalently, 0x7FFFFFFF , is the maximum signed 32-bit number. rdrand eax can put any value from 0x00000000 to 0xFFFFFFFF in eax . You have a few choices for how to handle this:

  1. Compare it with 4294967295 , or equivalently 0xFFFFFFFF , the maximum unsigned 32-bit number, instead.
  2. Do cmp eax, 2147483647 instead of cmp rax, 2147483647 . Since jle operates on the result of comparing signed integers, this will cause what you're now seeing as 2147483648 through 4294967295 to instead be interpreted as -2147483648 through -1 .
  3. Instead of having the upper 32 bits of rax always be zero, have them match the sign bit of eax instead (this is known as sign-extending ). You can do this by doing movsx rax, eax right after rdrand eax . This will cause rax to hold a value between -2147483648 and 2147483647 instead of between 0 and 4294967295 .

Any of those changes will result in your conditional jump always being taken, as you expect. If you want rax to end up being between 0 and 4294967295 , then choose option 1 or 2. If you want rax to end up being between -2147483648 and 2147483647 , then choose option 3.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM