Сгенерировать случайное число с заданным диапазоном с помощью команды rdrand

#casting #x86 #x86-64 #sse #mov

#Кастинг #x86 #x86-64 #sse #mov

Вопрос:

Вот моя цель: я хочу сгенерировать случайное число в сборке x86_64 с учетом начала и остановки. Вот моя идея сделать это на псевдо-Python:

 def rand_bounded(start, stop):
    return (start / stop) * rand32()
  

Таким образом rdrand eax , я могу получить случайное 32-разрядное число в eax регистре. Затем я могу start перейти xmm0 и разделить xmm0 со вторым аргументом в стеке. Это должно меня start / stop понять. Затем я должен иметь возможность умножить случайное 32-разрядное число на это; давайте назовем это A . cvtss2si похоже, правильная инструкция для округления A до ближайшего целого числа, основываясь на его описании здесь .

Моя проблема возникает при фактической попытке написать это. Каждый раз, когда я запускаю свой код (Clang, macOS), я получаю код выхода, равный нулю, что означает, что результат вычисляется неправильно (я перемещаю результат туда, где находится код выхода, rdi , ниже). Я предполагаю, что это связано с каким-то смешиванием 64-разрядных и 32-разрядных чисел, но кроме этого я понятия не имею, что вызывает сбой. Кто-нибудь, разбирающийся в сборке x86_64, знает, что я делаю неправильно?

     .global _main
    .data

float_storage:
    .int 0

    .text

rand_bounded:
    push rbp
    mov rbp, rsp

    movss xmm0, [rbp   16]
    divss xmm0, [rbp   24]  # xmm0 = start / stop

    rdrand eax
    mov [float_storage   rip], eax  # float_storage = rand()

    movss xmm1, [float_storage   rip]
    mulss xmm0, xmm1  # xmm0 *= float_storage
    cvtss2si eax, xmm0  # use movd?

    mov rsp, rbp
    pop rbp
    ret

_main:
    push 10  # stop
    push 5  # start
    call rand_bounded
    add rsp, 8

    mov rdi, rax
    mov rax, 0x2000001
    syscall
  

Комментарии:

1. push 10 и push 5 помещайте целочисленные значения в стек, но затем вы обрабатываете их как значения с плавающей запятой одинарной точности. Кроме того, системный вызов exit вернет только значение от 0 до 255.

2. @MichaelPetch Для вашего первого пункта, как мне преобразовать целочисленные значения стека в значения с плавающей запятой с одинарной точностью? Что касается вашего второго пункта, я согласен с тем, что системный вызов exit выполняет это, поскольку мое ожидаемое случайное число составляет всего от 5 до 10.

3. Просто наблюдение. Как (start / stop)*random32bitnumber дает значение между start и stop?

4. Мне любопытно. Являются ли начальные и конечные целочисленные значения и возвращаются ли значения целыми числами или вы действительно хотите вернуть число с плавающей запятой между 2 числами с плавающей запятой? Если это все целые числа, то здесь нет необходимости в числах с плавающей запятой. Вы могли бы использовать целочисленную div инструкцию, которая вернет остаток (по модулю). Чтобы получить целое число в диапазоне из 2 целых чисел (start и stop), вы могли бы сделать start (rand32 mod (stop-start)) . Конечно, будет смещение по модулю, но это другая проблема.

5. @MichaelPetch Спасибо, ваш метод сработал!