【赤石C++】详解达夫设备

admin 2026-02-03 01:18:06 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 达夫设备是C/C++中利用switch穿透特性展开循环的优化技术,旨在减少串行复制时的分支跳转次数。通过将8次操作打包并结合switch处理余数,该技术显著降低了循环开销,适用于编译器优化弱的早期环境。文章解析了其原理与memcpy实现,展示了手动展开提升性能的经典技巧。 综合评分: 93 文章分类: 二进制安全,逆向分析,代码审计


cover_image

【赤石C++】详解达夫设备

原创

crackme.net crackme.net

crackme安全实验室

2026年2月2日 00:11 河南

达夫设备

达夫设备(Duff’s device)是 C/C++ 语言中一种串行复制的优化技术,巧妙地利用了 switch 语句的穿透(fallthrough)特性

在早期计算机系统中,编译器优化能力弱,无法自动展开循环,且 CPU 流水线简单,几乎不存在分支预测。因此手动减少分支跳转次数能显著提升性能

考虑一个最简单的 memcpy 函数:

void mymemcpy(const uint8_t* src, uint8_t* dst, size_t size) noexcept {
&nbsp; &nbsp;&nbsp;for&nbsp;(size_t&nbsp;i =&nbsp;0; i < size; ++i) {
&nbsp; &nbsp; &nbsp; &nbsp; dst[i] = src[i];
&nbsp; &nbsp; }
}

每次循环都要执行:

  1. 1. 判断条件(i < size) -> 一次比较
  2. 2. 条件跳转(如果为 true,跳回循环体开头,否则跳出) -> 一次分支
  3. 3. 更新计数器(++i

所以,总共需要 N 次分支跳转(即 N 次条件判断 + 跳转)

达夫设备以 8 次操作为一组展开循环。其原理是:

  • • 初始时,利用 switch 直接跳到对应位置处理余数
  • • 后续全部通过 do-while 循环批量处理完整的一组(8 次)
  • • 每 8 次操作才做一次循环条件判断和跳转
void&nbsp;mymemcpy_duff(const&nbsp;uint8_t* src,&nbsp;uint8_t* dst,&nbsp;size_t&nbsp;size)&nbsp;noexcept&nbsp;{
&nbsp; &nbsp;&nbsp;size_t&nbsp;n = (size +&nbsp;7) /&nbsp;8;
&nbsp; &nbsp;&nbsp;switch&nbsp;(size %&nbsp;8) {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;0:&nbsp;do&nbsp;{ *dst++ = *src++;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;7: &nbsp; &nbsp; &nbsp;*dst++ = *src++;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;6: &nbsp; &nbsp; &nbsp;*dst++ = *src++;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;5: &nbsp; &nbsp; &nbsp;*dst++ = *src++;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;4: &nbsp; &nbsp; &nbsp;*dst++ = *src++;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;3: &nbsp; &nbsp; &nbsp;*dst++ = *src++;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;2: &nbsp; &nbsp; &nbsp;*dst++ = *src++;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;1: &nbsp; &nbsp; &nbsp;*dst++ = *src++;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;while&nbsp;(--n >&nbsp;0);
&nbsp; &nbsp; }
}

考虑 size = 100 的情况,100 除 8 等于 12 余 4,所以达夫设备需要进行 13 次循环,12 次完整处理 8 字节,1 次处理余下的 4 字节

  • • 计算循环次数:n = (100 + 7) / 8 = 13
  • • 处理 4 字节余数:size % 8 = 4,进入case 4分支,同时也进入do-while循环
case&nbsp;4: *dst++ = *src++;
case&nbsp;3: *dst++ = *src++;
case&nbsp;2: *dst++ = *src++;
case&nbsp;1: *dst++ = *src++;
  • • 4次复制执行完成后,执行while (--n > 0)n从13减到12,并进行条件判断
  • • n > 0的判断成立,do-while跳回循环体开头,执行 8 次完整复制
case&nbsp;0: *dst++ = *src++;
case&nbsp;7: *dst++ = *src++;
case&nbsp;6: *dst++ = *src++;
case&nbsp;5: *dst++ = *src++;
case&nbsp;4: *dst++ = *src++;
case&nbsp;3: *dst++ = *src++;
case&nbsp;2: *dst++ = *src++;
case&nbsp;1: *dst++ = *src++;
  • • 8 次完整复制执行完后,更新计数器,进行判断,跳回循环体开头,依次往复,直到计数器归 0

完整复制 100 字节,普通的 memcpy 需要 100 次分支跳转,而达夫设备仅需要 13 次

题外话

在特定语境下,device手段/技巧的意思(比如literary device翻译为文学手法而不是文学设备) ,所以Duff's Device更信达雅的翻译是达夫巧构(意为巧妙编程技巧

参考

https://zh.wikipedia.org/wiki/%E8%BE%BE%E5%A4%AB%E8%AE%BE%E5%A4%87

往期赤石 C++ 系列

【赤石C++】不使用宏,实现一个幂运算符

【赤石C++】不使用宏,实现一个“逆序”的成员访问运算符


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:crackme安全实验室 crackme.net crackme.net《【赤石C++】详解达夫设备》

评论:0   参与:  0