相关疑难解决方法(0)

Why does Windows64 use a different calling convention from all other OSes on x86-64?

AMD has an ABI specification that describes the calling convention to use on x86-64. All OSes follow it, except for Windows which has it's own x86-64 calling convention. Why?

Does anyone know the technical, historical, or political reasons for this difference, or is it purely a matter of NIHsyndrome?

I understand that different OSes may have different needs for higher level things, but that doesn't explain why for example the register parameter passing order on Windows is rcx - rdx …

windows x86-64 calling-convention

97
推荐指数
4
解决办法
2万
查看次数

试图理解gcc选项-fomit-frame-pointer

我让Google告诉我该gcc选项的含义-fomit-frame-pointer,它将我重定向到以下声明.

-fomit帧指针

不要将帧指针保存在寄存器中以查找不需要的函数.这避免了保存,设置和恢复帧指针的指令; 它还在许多功能中提供额外的寄存器.它还使某些机器无法进行调试.

根据我对每个函数的了解,将在进程内存的堆栈中创建激活记录,以保留所有局部变量和更多信息.我希望这个帧指针意味着一个函数的激活记录的地址.

在这种情况下,什么是函数类型,它不需要将帧指针保持在寄存器中?如果我得到这个信息,我会尝试设计基于它的新函数(如果可能),因为如果帧指针没有保存在寄存器中,一些指令将在二进制中省略.在具有许多功能的应用程序中,这将显着提高性能.

c optimization performance gcc

74
推荐指数
3
解决办法
5万
查看次数

为什么循环指令慢?英特尔无法有效实施吗?

LOOP(英特尔参考手动输入)递减ecx/rcx,然后如果非零则跳转.这很慢,但是英特尔不能廉价地把它变得很快吗? dec/jnz已经将宏观融合成 Sandybridge家族的一个 uop; 唯一的区别是设置标志.

loop关于各种微体系结构,来自Agner Fog的说明表:

  • K8/K10:7 m-ops
  • Bulldozer-family/Ryzen:1 m-op(与宏观融合测试和分支相同,或者jecxz)

  • P4:4次(相同jecxz)

  • P6(PII/PIII):8次
  • Pentium M,Core2:11 uops
  • Nehalem:6个uops.(11为loope/ loopne).吞吐量= 4c(loop)或7c(loope/ne).
  • SnB家族:7个uops.(11为loope/ loopne). 吞吐量=每5个循环一个,这是将循环计数器保留在内存中的瓶颈!jecxz只有2 uops,吞吐量与普通吞吐量相同jcc
  • Silvermont:7次
  • AMD Jaguar(低功耗):8 uops,5c吞吐量
  • 通过Nano3000:2 uops

难道解码器不能像lea rcx, [rcx-1]/ 那样解码jrcxz吗?这将是3 uops.至少那是没有地址大小前缀的情况,否则它必须使用ecx和截断RIP,EIP如果跳转; 也许奇怪的地址大小选择控制减量的宽度解释了许多uops?

或者更好,只需将其解码为不设置标志的融合分支和分支? dec ecx …

performance x86 assembly intel cpu-architecture

53
推荐指数
3
解决办法
6096
查看次数

为什么x86寄存器的命名方式如何?

例如,累加器被命名EAX,并且在调用指令指针时IP.我也知道有些字节叫做CLDH.我知道所有名字都必须有一个约定,但它是什么?

x86 assembly history naming

23
推荐指数
5
解决办法
3882
查看次数

什么是局部标志失速?

我刚刚查看了彼得·科德斯(Peter Cordes)的回答,他说,

如果读取标志,则部分标志停顿会发生,如果它们确实发生的话。P4永远不会有部分标志停顿,因为它们永远不需要合并。相反,它具有错误的依赖关系。几个答案/评论混淆了术语。它们描述了一个错误的依赖关系,但随后将其称为部分标志停顿。这是由于仅写入一些标志而导致的速度下降,但是术语“部分标志停顿”是指必须合并部分标志写入时在SnB之前的Intel硬件上发生的情况。英特尔SnB系列CPU插入一个额外的uop来合并标志而不会停顿。Nehalem和更早的失速约7个周期。我不确定AMD CPU会受到多大的损失。

我感觉我还不明白什么是“部分国旗摊位”。我怎么知道一个人发生了?除了读取标志的某些时间之外,什么触发事件?合并标志是什么意思?在什么情况下会“写一些标志”,但不会发生部分标志合并?我需要了解哪些有关旗位的知识才能理解它们?

x86 assembly

6
推荐指数
1
解决办法
291
查看次数

编写程序集时使用哪些寄存器重要吗?

如果您正在编写程序集,那么将值分配给哪个寄存器重要吗?假设您将累积/中间值存储在 %ebx 而不是 %eax 中,后者传统上用于此目的。这是不好的做法吗?会影响性能吗?

换句话说,您是否可以将它们等同于存储空间,还是应该坚持将它们用于特定目的?

x86 assembly cpu-registers accumulator

6
推荐指数
4
解决办法
1194
查看次数

x86汇编 - 为什么[e] bx保留在调用约定中?

我注意到很多调用约定都坚持为被调用者保留[e] bx.

现在,我可以理解为什么他们会保留像[e] sp或[e] bp这样的东西,因为这会弄乱被调用者的堆栈.我也可以理解为什么你可能想要保留[e] si或[e] di,因为如果他们不是特别小心的话可以打破被调用者的字符串指令.

但是[e] bx?究竟是什么对[e] bx如此重要?是什么让[e] bx如此特殊以至于多个调用约定都坚持在整个函数调用中保留它?

是否有某种微妙的错误/陷阱可能会因为[e] bx的混乱而产生?

修改[e] bx对被调用者的影响是否比修改[e] dx或[e] cx更大?

我只是不明白为什么这么多的召唤惯例单独列出[e] bx进行保存.

x86 assembly calling-convention

5
推荐指数
3
解决办法
924
查看次数

RAX,RBX,RCX,RDX,RSI,RDI,RBP,RSP,R8-R15是否可互换?

x64寄存器是否可以互换,因为任何与它们组合使用的指令都可以与其他指令一起使用?除了名称之外,是否有性能差异或任何其他因素使它们彼此不同?

assembly x86-64

4
推荐指数
2
解决办法
1592
查看次数

编译器是否通常将寄存器用于其“预期”目的?

我一直在学习汇编,并且我读到四个主要的 x86 通用寄存器(eax、ebx、ecx 和 edx)每个都有一个预期或建议的用途。例如,eax 是累加器寄存器,ecx 用作循环的计数器,等等。大多数编译器是否尝试将寄存器用于建议的目的,或者他们是否忽略了寄存器“应该”的用途而只是将值分配给下一个可用的寄存器?

此外,在查看 x64 寄存器时,我注意到添加了额外的 8 个通用寄存器,如果忽略 rbp、rsp、rsi 和 rdi(因为它们具有非通用用途),gp 寄存器的总数将达到 12 ),如果包括它们,则为十六个。在普通用户程序(即浏览器、文字处理器等,而不是需要大量寄存器的密码程序)中,在任何给定时间通常使用多少这些寄存器?像 Firefox 这样的程序一次使用所有 12/16 个普通寄存器是常见的,还是因为它们没有足够的变量来填充它们而只使用一个子集?我将通过反汇编二进制文件来自己研究这个问题,看看一般情况是什么,但我希望能得到比我更有见识的人的回答。

此外,如果当前未用于非通用应用程序,编译器是否通常将 semi-gp 寄存器(rsi、rdi、rsp 和 rbp)用于通用用途?我很好奇,因为我看到这些寄存器被列为“通用”,但即使我能想到这些寄存器不能用于通用存储的实例(例如,你不想存储rbp 和 rsp 变量,然后将值推入堆栈!)。那么编译器会尽量使用这些寄存器吗?x86 和 x64 编译之间是否有区别,因为 x64 处理器有更多可用寄存器,因此没有必要将变量填充到任何可用寄存器中?

compiler-construction x86 assembly compilation x86-64

4
推荐指数
1
解决办法
559
查看次数

哪些汇编指令或场景明确要求使用 RCX、ECX、CX 或 CL 计数器寄存器?

读完这个问题后为什么 %cl 是 sal 操作接受作为参数的唯一寄存器?,我很好奇还有哪些指令需要计数寄存器?

\n

循环控制

\n

LOOP 指令假定 CX、ECX 或 RCX 寄存器包含循环计数。

\n
loop\nloopnz\nloopne\nloopz\nloope\n
Run Code Online (Sandbox Code Playgroud)\n

跳跃

\n

如果 CX、ECX 或 RCX 寄存器为零,则执行跳转的跳转指令。

\n
jcxz\njecxz\njrcxz\n
Run Code Online (Sandbox Code Playgroud)\n

重复前缀

\n

这些重复前缀与字符串指令一起使用并使用计数寄存器。

\n
rep\nrepe\nrepz\nrepne\nrepnz\n
Run Code Online (Sandbox Code Playgroud)\n

位移位

\n

逻辑、移位、循环和位指令(省略了双字和四字变体,例如 shld、shlq...)

\n
shl\nshr\nsal\nsar\nrol\nror\nrcl\nrcr\n
Run Code Online (Sandbox Code Playgroud)\n

Fastcall 调用约定

\n

参数列表中从左到右找到的前两个 DWORD 或更小的参数被传入ECXEDX 寄存器;所有其他参数都在堆栈上从右向左传递。

\n
__attribute__((fastcall)) void printnums(int num1, int num2, int num3){\n    printf("The numbers you sent are: %d %d %d", num1, num2, num3);\n}\n\nint main(){\n    printnums(1, 2, 3);\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

Microsoft x64 …

assembly x86-64 masm nasm calling-convention

3
推荐指数
1
解决办法
109
查看次数