当前位置: 首页 > 知识库问答 >
问题:

将ASM指令RDRand转换为Win64

慕意致
2023-03-14

我有这个函数(RDRand-由David Heffernan编写),它可以在32位中正常工作,但在64位中失败:

function TryRdRand(out Value: Cardinal): Boolean;
{$IF defined(CPU64BITS)}
asm .noframe
{$else}
asm
{$ifend}
  db   $0f
  db   $c7
  db   $f1
  jc   @success
  xor  eax,eax
  ret
@success:
  mov  [eax],ecx
  mov  eax,1
end;

函数的文档在这里:https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide

特别是上面写着:

本质上,开发人员使用单个操作数调用此指令:存储随机值的目标寄存器。请注意,该寄存器必须是通用寄存器,寄存器的大小(16、32或64位)将决定返回的随机值的大小。

调用RDRAND指令后,调用者必须检查进位标志(CF)以确定在执行RDRAND指令时随机值是否可用。如表3所示,值1表示随机值可用并放置在调用中提供的目标寄存器中。值0表示随机值不可用。在当前架构中,作为此条件的副作用,目标寄存器也将被归零。

我对ASM的了解很低,我错过了什么?

此外,我不太理解此说明:

  ...
  xor  eax,eax
  ret
  ...

它到底是做什么的?

共有1个答案

亢正德
2023-03-14

如果您想要一个执行完全相同的函数,那么我认为如下所示:

function TryRdRand(out Value: Cardinal): Boolean;
asm
{$if defined(WIN64)}
  .noframe
  // rdrand eax
  db   $0f
  db   $c7
  db   $f0
  jnc  @fail
  mov  [rcx],eax
{$elseif defined(WIN32)}
  // rdrand ecx
  db   $0f
  db   $c7
  db   $f1
  jnc  @fail
  mov  [eax],ecx
{$else}
{$Message Fatal 'TryRdRand not implemented for this platform'}
{$endif}
  mov  eax,1
  ret
@fail:
  xor  eax,eax
end;

Peter Cordes提出的在ash中实现重试循环的建议在我看来是明智的。我不会在这里尝试实现它,因为我认为它有点超出了你的问题范围。

此外,Peter指出,在x64中,您可以读取具有REX. W=1前缀的64位随机值。这看起来像这样:

function TryRdRand(out Value: NativeUInt): Boolean;
asm
{$if defined(WIN64)}
  .noframe
  // rdrand rax
  db   $48  // REX.W = 1
  db   $0f
  db   $c7
  db   $f0
  jnc  @fail
  mov  [rcx],rax
{$elseif defined(WIN32)}
  // rdrand ecx
  db   $0f
  db   $c7
  db   $f1
  jnc  @fail
  mov  [eax],ecx
{$else}
{$Message Fatal 'TryRdRand not implemented for this platform'}
{$endif}
  mov  eax,1
  ret
@fail:
  xor  eax,eax
end;
 类似资料:
  • 概要 <transform transVar> ... </transform> or <transform transVar name1=value1 name2=value2 ... nameN=valueN> ... </transform> 这里: transVar: 要来转换的表达式 name1, name2,... nameN: 参数的名称。文字值,不是表达式 value1

  • 我正在尝试理解OpenSSL中使用的x86汇编函数,以使用CPU的RDRAND指令获取随机字节。这是函数体: 我不知道cmp和cmobile指令的用途。我不是x86汇编程序员,但从我看过的参考文献中可以看出,我对它的作用的理解是: 因此,如果rdrand失败,rax只能为0(进位标志是明确的),并且只有当1)rdrand成功(进位设置)并在rax中放入非零数字,或2)ecx中的重试计数器已减为0时

  • 问题内容: 的在系统调用 包在Golang返回类型,而底层系统调用实际上返回一个指针。它是如何做到的? 更具体地说,在Golang开发人员的此程序包中,该函数仅返回一个指针。如何将其转换为字节片,就像在Unix软件包中一样? 问题答案: 使用该包,您可以在未导出类型的Mmap方法中执行相同的操作: 这是一个操场的例子。

  • 5、类型转换指令 在作有符号除法时,有时需要把短位数的被除数转换成位数更长的数据类型。比如,要用BL中的数据去除AL,但根据除法指令的规定:除数是8位,则被除数必须是AX,于是就涉及到AH的取值问题。 为了方便说明,假设:(AH)=1H,(AL)=90H=-112D,(BL)=10H。 1)、在作除法运算前,必须处理AH的原有内容 假设在作除法时,不管AH中的值,这时,(AH、AL)/BL的商是1

  • 问题内容: 如果我有: 上面是固定的-我不能更改foo或bar。另外,baz必须在bar内转换回foo struct指针。如何将&foo {}强制转换为interface {},以便在调用bar时可以将其用作参数? 问题答案: 要打开到一个很简单: 为了返回到,您可以执行 类型断言 : 或 类型开关 (类似,但可以是多种类型则很有用):

  • 当使用来自外部库的函数时,“任意”取消引用指向const引用的指针是否安全? 这样做是否普遍安全/明智 更重要的是,除了C语言中“不赞成”的原始指针之外,使用常量指针真的有充分的理由这样做吗?