Assembly 在MUSL'中进行系统调用之前,在堆栈上保存传入pthread地址的目的;s x86\u 64\u系统调用\u cp\u asm包装器?

Assembly 在MUSL'中进行系统调用之前,在堆栈上保存传入pthread地址的目的;s x86\u 64\u系统调用\u cp\u asm包装器?,assembly,x86-64,musl,Assembly,X86 64,Musl,这是代码: 我很好奇第6行和第14行的目的是什么(从链接来源重新编号) 据我所知,代码的开头测试了作为第一个参数传递的指针的目标(第3-5行),第6行将指针移动到r11,第14行将指针移动到堆栈上用于传递第七个参数的位置 这似乎没用。这些移动完成了什么吗?第7-14行中的代码按参数顺序将参数加载到系统调用中。由于RDI是在第8行加载的,所以它的值保存在R11中,以便可以将其写入第14行的参数8(堆栈上) 在手工编写的汇编代码中,通过保持这样的组织方式可以更容易理解和维护,这超过了额外移动指令的成

这是代码:

我很好奇第6行和第14行的目的是什么(从链接来源重新编号)

据我所知,代码的开头测试了作为第一个参数传递的指针的目标(第3-5行),第6行将指针移动到r11,第14行将指针移动到堆栈上用于传递第七个参数的位置


这似乎没用。这些移动完成了什么吗?

第7-14行中的代码按参数顺序将参数加载到系统调用中。由于RDI是在第8行加载的,所以它的值保存在R11中,以便可以将其写入第14行的参数8(堆栈上)


在手工编写的汇编代码中,通过保持这样的组织方式可以更容易理解和维护,这超过了额外移动指令的成本。

第7-14行中的代码按参数顺序将参数加载到系统调用。由于RDI是在第8行加载的,所以它的值保存在R11中,以便可以将其写入第14行的参数8(堆栈上)


在手工编写的汇编代码中,通过保持这样的组织,可以更容易理解和维护,这超过了额外移动指令的成本。

这是为了支持pthread取消点;信号处理程序稍后可以查看堆栈

说明了在系统调用之前将指针存储在堆栈上的已知位置,使“取消信号处理程序”能够确定“中断的代码是否处于可取消状态”。(该代码的初始版本还保存了
syscall
指令的地址,但后来更改了该地址。)

第一个参数(asm函数存储在堆栈上)来自,
\uuu syscall\u cp\u c
,它传递
\uuu syscall\u cp\u asm(&self->cancel,nr,u,v,w,x,y,z)
,其中
self
来自
\uuupthread\uself()


您是正确的,使用不同的传入参数覆盖调用方的堆栈参数对x86-64 System V ABI之后的C调用方来说是不“可见”的。(被调用方拥有其堆栈参数;调用方必须假设它们已被覆盖,这样编译器生成的代码将永远不会将该内存位置作为输出读取)。所以我们需要寻找其他解释


我认为有必要在读取内存位置后使用2条mov指令将传入RDI复制到
8(%rsp)
。我们不能将
mov%rdx,%rdi延迟到加载之后,因为我们需要释放rdx以保持R8,释放R8以保持加载。在使用R10加载另一个arg之前,可以避免接触“额外”寄存器,但至少需要2条指令


或者,可以优化arg顺序,以便在以后的arg中传递该指针,也可以在最后一个寄存器arg中传递调用号和pthread指针(最小程度的洗牌,但避免对该测试/分支进行双解引用)或第一个堆栈arg(您仍然需要它的地方)。或者匹配首先接受
nr
且没有pthread指针的
\uu系统调用
包装的参数顺序。

这是为了支持pthread取消点;信号处理程序稍后可以查看堆栈

说明了在系统调用之前将指针存储在堆栈上的已知位置,使“取消信号处理程序”能够确定“中断的代码是否处于可取消状态”。(该代码的初始版本还保存了
syscall
指令的地址,但后来更改了该地址。)

第一个参数(asm函数存储在堆栈上)来自,
\uuu syscall\u cp\u c
,它传递
\uuu syscall\u cp\u asm(&self->cancel,nr,u,v,w,x,y,z)
,其中
self
来自
\uuupthread\uself()


您是正确的,使用不同的传入参数覆盖调用方的堆栈参数对x86-64 System V ABI之后的C调用方来说是不“可见”的。(被调用方拥有其堆栈参数;调用方必须假设它们已被覆盖,这样编译器生成的代码将永远不会将该内存位置作为输出读取)。所以我们需要寻找其他解释


我认为有必要在读取内存位置后使用2条mov指令将传入RDI复制到
8(%rsp)
。我们不能将
mov%rdx,%rdi延迟到加载之后,因为我们需要释放rdx以保持R8,释放R8以保持加载。在使用R10加载另一个arg之前,可以避免接触“额外”寄存器,但至少需要2条指令


或者,可以优化arg顺序,以便在以后的arg中传递该指针,也可以在最后一个寄存器arg中传递调用号和pthread指针(最小程度的洗牌,但避免对该测试/分支进行双解引用)或第一个堆栈arg(您仍然需要它的地方)。或者匹配首先接受
nr
且没有pthread指针的
\uu系统调用
包装的参数顺序。

从何处调用?调用方是否也可以是手工编写的asm,该asm将在该函数返回后查看
(%rsp)
?RDI似乎是某种内部使用指针,因此调用号在RSI中,syscall args在后面的插槽中。我同意,如果调用方采用正常的x86-64 SysV调用约定,则在堆栈arg上存储传入RDI的副本没有任何意义;这不是打电话的人会看到的。除非返回地址实际上是另一个函数的地址?但这会使堆栈错位,因此在完全标准的x86-64 SysV中无法执行。@PeterCordes它仅从@PeterCordes调用,谢谢。我正在根据我自己的目的修改它,在进行修改的同时,这两行
 1  __syscall_cp_asm:
 2  __cp_begin:
 3      mov (%rdi),%eax
 4      test %eax,%eax
 5      jnz __cp_cancel

 6      mov %rdi,%r11

 7      mov %rsi,%rax
 8      mov %rdx,%rdi
 9      mov %rcx,%rsi
10      mov %r8,%rdx
11      mov %r9,%r10
12      mov 8(%rsp),%r8
13      mov 16(%rsp),%r9

14      mov %r11,8(%rsp)

15      syscall
16  __cp_end:
17      ret
18  __cp_cancel:
19      jmp __cancel