汇编 cmp_1_协程的汇编实现

本文介绍了libgo协程基于boost fcontext的实现,探讨了汇编基础知识,包括Directives、标签、x86_64寄存器、数据大小、函数调用约定等。重点解析了jump_fcontext和make_fcontext的实现,特别是预留72字节栈空间以简化jump_fcontext行为的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

libgo的协程是基于boost的fcontex接口。实现简单而且高效。理解汇编实现后,能够更好地理解协程以及协程间的切换。

1.汇编相关的基础知识(个人见解)

1)Directives

指示对编译器,链接器,调试器有用的结构信息

.file 源文件名

.data .file .string

.globl main :指明标签main是一个可以在其他模块中被访问的全局符号

2)标签

Tags: 可用于跳转 也可用作别名替换

以.开始的标签是编译器生成的临时局部标签

3)x86_64含有16个64为整数寄存器

%rsi,%rdi 用于字符串处理

%rsp,%rbp 栈相关,栈从高地址到低地址 %rsp ---> 栈顶,push和pop会改变 %rbp ---> 栈基址

%8~%15

4)操作的数据大小

B Byte

W Word 2Byte

L Long 4Byte

Q QuadWord 8Byte

5)函数的调用约定

a.整型参数依次存放在 %rdi,%rsi,%rdx,%rcx,%8,%9

b.浮点参数依次存放在%xmm0 - %xmm7中

c.寄存器不够用时,参数放到栈中

d.被调用的函数可以使用任何寄存器,但它必须保证%rbx,%rbp,%rsp,and %12-%15恢复到原来的值

e.返回值存放在%rax中

6)调用函数前

调用方要将参数放到寄存器中

然后把%10,%11的值保存到栈中

然后调用call 跳转到函数执行

返回后,恢复%10,%11

从%eax中取出返回值

2.jump_fcotext的实现

intptr_t jump_fcontext(fcontext_t * ofc,                    
                       fcontext_t nfc,
                       intptr_t vp,
                       bool preserve_fpu = false);
简单说明:调用时会将当前的上下文保存到ofc中.并切换到目标上下文nfc进行执行.

.text
.globl jump_fcontext                        //声明jump_fcontext为全局可见的符号
.type jump_fcontext,@function
.align 16
jump_fcontext:

   //被调用的函数有责任保存这些寄存器  
    pushq  %rbp  /* save RBP */
    pushq  %rbx  /* save RBX */
    pushq  %r15  /* save R15 */
    pushq  %r14  /* save R14 */
    pushq  %r13  /* save R13 */
    pushq  %r12  /* save R12 */
 
    //rsp栈顶下移8字节 --->prepare stack for FPU 浮点运算寄存器 
    leaq  -0x8(%rsp), %rsp
 
    //整数参数依次存放在 %rdi,%rsi,%rdx,%rcx,%8,%9
    cmp  $0, %rcx             //rcx:第四个参数 preserve_fpu
    je  1f                    //先不考虑fpu相关
 
    // 保存MXCSR内容 rsp 寄存器
    stmxcsr  (%rsp)
    // 保存当前FPU状态字到 rsp+4 的位置
    fnstcw   0x4(%rsp)
 
1:
    movq  %rsp, (%rdi)        //rdi:fdcontext* ofc   
                              //,当前的栈顶保存到ofc中 ----> 源上下文
 
    movq  %rsi, %rsp          //rsi:fdcontext nfc  ---> 目标上下文.
 
    /* test for flag preserve_fpu */
    cmp  $0, %rcx
    je  2f
 
    /* restore MMX control- and status-word */
    ldmxcsr  (%rsp)
    /* restore x87 control-word */
    fldcw  0x4(%rsp)
 
2:  
    leaq  0x8(%rsp), %rsp    //栈顶上移8字节 ----> prepare stack for FPU 
 
   //此时rsp保存着目标上下文
   //恢复这些寄存器 ----> 恢复目标上下文的环境
    popq  %r12  /* restrore R12 */
    popq  %r13  /* restrore R13 */
    popq  %r14  /* restrore R14 */
    popq  %r15  /* restrore R15 */
    popq  %rbx  /* restrore RBX */
    popq  %rbp  /* restrore RBP */
 
    popq  %r8           //目标上下文切换之前的下一条指令地址,这个要结合make_fcontext
    
    //用第三个参数作为返回值
    movq %rdx,%rax            //rax用作返回值
    //将第三个参数作为目标上下文启动函数的第一参数 ---> 结合make_fcontext理解
    movq  %rdx, %rdi     
    
    jmp  *%r8              //跳转到目标上下文的代码处执行
.size jump_fcontext,.-jump_fcontext

2.make_fcontext的实现

fcontext_t make_fcontext(void* stack, 
                         size_t size, 
                         fn_t fn);
简单说明:创建上下文:启动函数+执行栈
bl make_fcontext
.type make_fcontext,@function
.align 16
make_fcontext:

    movq  %rdi, %rax      //rdi为第一参数: stack

    andq  $-16, %rax       //将地址取为16的整数倍  
                           //-16补码:0xfffffff0


    //预留72字节的栈空间

    /* reserve space for context-data on context-stack */
    /* size for fc_mxcsr .. RIP + return-address for context-function */
    /* on context-function entry: (RSP -0x8) % 16 == 0 */
    leaq  -0x48(%rax), %rax              //以此时rax的地址为基点
    
    //启动函数入口地址保存在0x38处
    movq  %rdx, 0x38(%rax)     //rdx为第三参数: fn


    //FPU相关
    /* save MMX control- and status-word */
    stmxcsr  (%rax)
    /* save x87 control-word */
    fnstcw   0x4(%rax)

    /* compute abs address of label finish */  
    leaq  finish(%rip), %rcx          
    /* save address of finish as return-address for context-function */
    /* will be entered after context-function returns */
    movq  %rcx, 0x40(%rax)         //finish刚好位于启动函数上方 ---> 启动函数执行完以后就会执行finish处的代码 
                                   //而finish会调用_exit结束进程
    ret                            //rax就是上述的基点.返回的类型为fcontext_t

finish:
    /* exit code is zero */
    xorq  %rdi, %rdi
    /* exit application */
    call  _exit@PLT
    hlt
.size make_fcontext,.-make_fcontext

/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits

用一张图来帮助理解:

b9df9682620a181a04f5475f3c2251fc.png

可见fcontxt_t类型值就是上下文的标识

为什么make_fcontext()需要预留72字节的栈空间呢?不预留行吗?

当然也行,但会增加jump_fcontext()的代码,即要判断目标上下文是刚初始化好(上下文环境为空)的呢,还是已经调用过jump_fcontext()(上下文环境不为空,含有rbp这些寄存器),根据判断结果来做出不同的行为

预留72字节的栈空间,营造假想的上下文环境,来统一jump_fcontext()的行为

注意点: finish会结束进程 ---> 若代码最终切换到make_fcontext()生成的上下文环境中,那么最后就会结束进程

### RT-DETRv3 网络结构分析 RT-DETRv3 是一种基于 Transformer 的实时端到端目标检测算法,其核心在于通过引入分层密集正监督方法以及一系列创新性的训练策略,解决了传统 DETR 模型收敛慢和解码器训练不足的问题。以下是 RT-DETRv3 的主要网络结构特点: #### 1. **基于 CNN 的辅助分支** 为了增强编码器的特征表示能力,RT-DETRv3 引入了一个基于卷积神经网络 (CNN) 的辅助分支[^3]。这一分支提供了密集的监督信号,能够与原始解码器协同工作,从而提升整体性能。 ```python class AuxiliaryBranch(nn.Module): def __init__(self, in_channels, out_channels): super(AuxiliaryBranch, self).__init__() self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1) self.bn = nn.BatchNorm2d(out_channels) def forward(self, x): return F.relu(self.bn(self.conv(x))) ``` 此部分的设计灵感来源于传统的 CNN 架构,例如 YOLO 系列中的 CSPNet 和 PAN 结构[^2],这些技术被用来优化特征提取效率并减少计算开销。 --- #### 2. **自注意力扰动学习策略** 为解决解码器训练不足的问题,RT-DETRv3 提出了一种名为 *self-att 扰动* 的新学习策略。这种策略通过对多个查询组中阳性样本的标签分配进行多样化处理,有效增加了阳例的数量,进而提高了模型的学习能力和泛化性能。 具体实现方式是在训练过程中动态调整注意力权重分布,确保更多的高质量查询可以与真实标注 (Ground Truth) 进行匹配。 --- #### 3. **共享权重解编码器分支** 除了上述改进外,RT-DETRv3 还引入了一个共享权重的解编码器分支,专门用于提供密集的正向监督信号。这一设计不仅简化了模型架构,还显著降低了参数量和推理时间,使其更适合实时应用需求。 ```python class SharedDecoderEncoder(nn.Module): def __init__(self, d_model, nhead, num_layers): super(SharedDecoderEncoder, self).__init__() decoder_layer = nn.TransformerDecoderLayer(d_model=d_model, nhead=nhead) self.decoder = nn.TransformerDecoder(decoder_layer, num_layers=num_layers) def forward(self, tgt, memory): return self.decoder(tgt=tgt, memory=memory) ``` 通过这种方式,RT-DETRv3 实现了高效的目标检测流程,在保持高精度的同时大幅缩短了推理延迟。 --- #### 4. **与其他模型的关系** 值得一提的是,RT-DETRv3 并未完全抛弃经典的 CNN 技术,而是将其与 Transformer 结合起来形成混合架构[^4]。例如,它采用了 YOLO 系列中的 RepNCSP 模块替代冗余的多尺度自注意力层,从而减少了不必要的计算负担。 此外,RT-DETRv3 还借鉴了 DETR 的一对一匹配策略,并在此基础上进行了优化,进一步提升了小目标检测的能力。 --- ### 总结 综上所述,RT-DETRv3 的网络结构主要包括以下几个关键组件:基于 CNN 的辅助分支、自注意力扰动学习策略、共享权重解编码器分支以及混合编码器设计。这些技术创新共同推动了实时目标检测领域的发展,使其在复杂场景下的表现更加出色。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值