相关疑难解决方法(0)

为什么他们在x86-64中使用数字作为寄存器名称?

AFAIK X86-64增加了大量的通用寄存器的那些从英特尔86(派生rax,rcx等),被称为r8- r15.

他们为什么要这样命名新的寄存器?为什么不遵循现有的命名规则,并呼吁他们一样rfx,rgx...?

assembly x86-64 cpu-registers isa

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

当用户空间程序调用系统调用时,执行如何传回内核空间?

我一直在研究关于x86-64的ABI,编写汇编以及研究堆栈和堆如何工作的问题.

给出以下代码:

#include <linux/seccomp.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    // execute the seccomp syscall (could be any syscall)
    seccomp(...);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在Assembly for x86-64中,这将执行以下操作:

  1. 对齐堆栈指针(默认情况下,它关闭8个字节).
  2. 为调用的任何参数设置寄存器和堆栈seccomp.
  3. 执行以下程序集call seccomp.
  4. seccomp返回时,它可能是一,在C将调用exit(0)据我所知.

我想谈谈上面第三步和第四步之间发生的事情.

我目前拥有当前正在运行的进程的堆栈,它在寄存器和堆栈中有自己的数据.用户空间进程如何将执行转交给内核?内核只是在调用时接收,然后从同一堆栈中推送并弹出?

我相信我听说系统调用不会立即发生,而是在某些CPU滴答或中断时发生.这是真的?例如,在Linux上,这是怎么发生的?

c assembly kernel linux-kernel

3
推荐指数
2
解决办法
587
查看次数

按照每个通用寄存器的用途编写x86汇编是否必要或更容易

一般来说,按照每个寄存器的用途编码x86汇编是否必要或更容易?

x86架构中的寄存器每个都是首先设计用于特殊目的,但现代编译器似乎并不关心它们的使用(除非在某些特殊条件下,例如REP MOV或MUL).

那么,取决于每个寄存器的用途,代码是更容易还是更优化?(不管与某些寄存器相同的特殊指令(或编码))

例如(我可以改用REP MOVSB或LODSB STOSB,但只是为了演示):

第一个代码:

LEA ESI,[AddressOfSomething]
LEA EDI,[AddressOfSomethingElse]
MOV ECX,NUMBER_OF_LOOP
LoopHere:
MOV AL,[ESI]
ADD AL,8
MOV [EDI],AL
ADD ESI,1
ADD EDI,1
CMP AL,0
JNZ LoopHere
TheEnd:
;...
Run Code Online (Sandbox Code Playgroud)

第二代码:

LEA ECX,[AddressOfSomething]
LEA EDX,[AddressOfSomethingElse]
MOV EBX,NUMBER_OF_LOOP
LoopHere:
MOV AL,[ECX]
ADD AL,8
MOV [EDX],AL
ADD ECX,1
ADD EDX,1
CMP AL,0
JNZ LoopHere
TheEnd:
;...
Run Code Online (Sandbox Code Playgroud)

我使用的编译器 - Visual Studio 2015在执行这样的任务时通常使用第二种方法,它不使用寄存器取决于它的用途,相反,编译器只根据其"volatile"选择使用哪个寄存器或"非易失性"特征(在调用函数后).因此,所有高级编程语言编程软件反汇编都使用第二种方法.

另一个有趣的事实是,在ARM语言中,GPR都具有相同的用途,并且被命名为R0-R7,这意味着当代码使用它时,代码将更类似于第二代码.

总而言之,我的观点是这两个代码使用相同的指令,因此无论我使用哪个寄存器,它都应该具有相同的速度.但我是对的吗?哪个代码更容易编码?

c++ optimization x86 assembly cpu-registers

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

x86-64 分段错误保存堆栈指针

我目前正在学习本教程,但我不是该学校的学生。

GDB 给了我一个分段错误thread_start

movq  %rsp, (%rdi)   # save sp in old thread's tcb
Run Code Online (Sandbox Code Playgroud)

当我回溯时,这是附加信息:

#0  thread_start () at thread_start.s:16
#1  0x0000000180219e83 in _cygtls::remove(unsigned int)::__PRETTY_FUNCTION__
    () from /usr/bin/cygwin1.dll
#2  0x00000000ffffcc6b in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
Run Code Online (Sandbox Code Playgroud)

作为一个新手,我一生都无法弄清楚为什么。这是我的主文件:

#define STACK_SIZE 1024*1024

//Thread TCB
struct thread {
    unsigned char * stack_pointer;
    void(*initial_function)(void *);
    void * initial_argument;
};

struct thread * current_thread;
struct thread * inactive_thread;

void thread_switch(struct thread * old_t, struct thread …
Run Code Online (Sandbox Code Playgroud)

c x86 assembly cygwin x86-64

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

当前的 C++ 编译器是否曾经发出过“rep movsb/w/d”?

这个问题让我想知道,当前的现代编译器是否曾经发出REP MOVSB/W/D指令。

基于此讨论,似乎REP MOVSB/W/D在当前 CPU 上使用可能是有益的。

但无论我如何尝试,我都无法让当前的任何编译器(GCC 8、Clang 7、MSVC 2017 和 ICC 18)发出这条指令。

对于这个简单的代码,emit 可能是合理的REP MOVSB

void fn(char *dst, const char *src, int l) {
    for (int i=0; i<l; i++) {
        dst[i] = src[i];
    }
}
Run Code Online (Sandbox Code Playgroud)

但是编译器会发出一个未优化的简单字节复制循环,或者一个巨大的展开循环(基本上是内联的memmove)。是否有任何编译器使用此指令?

c++ x86 assembly micro-optimization compiler-optimization

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

我应该在哪里使用“swapgs”指令

您好,我是一名内核学习者,对 swapgs 有一些疑问。

根据 AMD 的文档,它交换了gs.base隐藏寄存器和 KernelGSBase MSR。

此外,“gs:XXXX”的寻址计算为“gs.base + base + (scale*index) +位移”


现在我的第一个问题是:

  1. gs.base 是段寄存器的隐藏部分
  2. 位移是“gs:XXXX”的“XXXX”部分
  3. index 可能是 gs 中的选择器索引

那么我应该在哪里存储“基础”和“比例”?


此外,我应该在哪里使用它,我当前的项目将虚拟内存空间的上半部分作为内核,并且编译器通常不会添加“gs:XXXX”作为寻址引用。

所以,特别是,我应该在哪里使用swapgs指令。

assembly operating-system kernel x86-64 thread-local-storage

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

x86汇编pushad/popad,它的速度有多快?

我只是试图在x86汇编中进行非常快速的基于计算的程序,但我需要在调用程序之前推送累加器,计数器和数据寄存器.手动推动它们的速度更快:

push eax
push ecx
push edx
Run Code Online (Sandbox Code Playgroud)

或者只是使用,

pushad
Run Code Online (Sandbox Code Playgroud)

与弹出一样.谢谢

performance x86 assembly inline-assembly micro-optimization

2
推荐指数
1
解决办法
1193
查看次数

Windows x64 调用约定中 R10-R15 寄存器的用途是什么?

来自 Intel 对 x64 汇编的介绍https://software.intel.com/en-us/articles/introduction-to-x64-assemble

  • RCX、RDX、R8、R9 按从左到右的顺序用于整数和指针参数。
  • 寄存器 RAX、RCX、RDX、R8、R9、R10 和 R11 被视为易失性寄存器,必须在函数调用时被视为已销毁。
  • RBX、RBP、RDI、RSI、R12、R14、R14 和 R15 必须保存在使用它们的任何函数中。

虽然我了解如何将 RCX、RDX、R8、R9 用作函数参数,但我见过使用 4 个以上参数的函数会恢复为使用堆栈(如 32 位代码)。示例如下:

sub_18000BF10   proc near 
lpDirectory     = qword ptr -638h
nShowCmd        = dword ptr -630h
Parameters      = word ptr -628h

             sub     rsp, 658h
             mov     r9, rcx
             mov     r8, rdx
             lea     rdx, someCommand ; "echo "Hello""...
             lea     rcx, [rsp+658h+Parameters] ; LPWSTR
             call    cs:wsprintfW
             xor     r11d, r11d
             lea     r9, [rsp+658h+Parameters] ; lpParameters
             mov     [rsp+658h+nShowCmd], r11d ; nShowCmd
             lea     r8, …
Run Code Online (Sandbox Code Playgroud)

assembly x86-64 calling-convention

2
推荐指数
1
解决办法
8809
查看次数

为什么要让一些寄存器由调用者保存而另一些寄存器由被调用者保存?为什么不让调用者保存它想要保存的所有内容?

在这篇关于寄存器保存的维基百科文章中,我读到调用者函数负责某些寄存器(以防止其先前的数据被更改),而被调用者则负责其他寄存器。

我的问题是为什么我们必须让事情复杂化?为什么不让所有寄存器成为调用者的责任,在调用函数之前备份现有值并在之后重新加载它们?

我没有看到执行这些步骤有任何性能提升,有人可以帮助我理解吗?

assembly cpu-registers calling-convention riscv

2
推荐指数
1
解决办法
2073
查看次数

声明var外部循环不好?

我为我正在制作的DSP /音频应用编写了这个基本代码:

double input = 0.0;
for (int i = 0; i < nChannels; i++) {
      input = inputs[i];
Run Code Online (Sandbox Code Playgroud)

一些DSP工程专家告诉我:"你不应该在循环之外声明它,否则它会创建一个依赖项,编译器无法尽可能高效地处理它."

input我在想他正在谈论var .为什么这个?是不是更好地去掉一次并覆盖它?

也许有些事情与不同的内存位置有关?即注册而不是堆栈?

c++ memory performance loops declaration

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