Linux中在字符串中查找指定字符的第一次出现位置的汇编实现

在字符串中查找指定字符的第一次出现位置strchr

c 复制代码
static inline char * strchr(const char * s, int c)
{
int d0;
register char * __res;
__asm__ __volatile__(
        "movb %%al,%%ah\n"
        "1:\tlodsb\n\t"
        "cmpb %%ah,%%al\n\t"
        "je 2f\n\t"
        "testb %%al,%%al\n\t"
        "jne 1b\n\t"
        "movl $1,%1\n"
        "2:\tmovl %1,%0\n\t"
        "decl %0"
        :"=a" (__res), "=&S" (d0) : "1" (s),"0" (c));
return __res;
}

1. 函数功能概述

这是一个用内联汇编实现的 strchr 函数,用于在字符串中查找指定字符的第一次出现位置

2. 代码分段详解

2.1. 第一段:函数声明和变量定义

c 复制代码
static inline char *strchr(const char *s, int c)
{
    int d0;
    register char *__res;
  • static inline 表示这是内联函数,调用时直接展开而不是函数调用
  • const char *s 是输入字符串指针
  • int c 是要查找的字符
  • int d0 用于存储临时值(在汇编中作为占位符)
  • register char *__res 声明寄存器变量,用于存储结果指针

2.2. 第二段:内联汇编开始和初始设置

c 复制代码
    __asm__ __volatile__(
        "movb %%al,%%ah\n\t"
  • __asm__ __volatile__ 开始内联汇编块,volatile 表示禁止编译器优化
  • movb %%al,%%ah 将字符 c(在 al 寄存器中)复制到 ah 寄存器中备份
    • %%al 对应参数 c(通过约束条件 "0" 传入)
    • 备份是因为 lodsb 指令会修改 al 寄存器

2.2. 第三段:字符串扫描循环

c 复制代码
        "1:\tlodsb\n\t"
        "cmpb %%ah,%%al\n\t"
        "je 2f\n\t"
        "testb %%al,%%al\n\t"
        "jne 1b\n\t"
  • 1:\tlodsb 标签1:加载字符串字节到 al,同时递增 esi 指针
  • cmpb %%ah,%%al 比较当前字符(al)与目标字符(ah
  • je 2f 如果相等,跳转到标签2
  • testb %%al,%%al 测试当前字符是否为0(字符串结束)
  • jne 1b 如果不是0,跳转回标签1(向后跳转),继续循环

2.3. 第四段:处理查找失败情况

c 复制代码
        "movl $1,%1\n\t"
  • movl $1,%1 将1移动到操作数1(d0 变量)
  • 这行代码只在查找失败(到达字符串末尾未找到字符)时执行

2.4. 第五段:处理查找成功情况

c 复制代码
        "2:\tmovl %1,%0\n\t"
        "decl %0"
  • 2:\tmovl %1,%0 标签2:将操作数1(d0esi)的值复制到操作数0(__res
  • decl %0 递减结果指针(因为 lodsb 在比较后自动递增了指针)

2.5. 第六段:汇编约束条件

c 复制代码
        : "=a" (__res), "=&S" (d0)
        : "1" (s), "0" (c));

输出操作数:

  • "=a" (__res)__res 变量绑定到 eax 寄存器(= 表示只写)
  • "=&S" (d0)d0 变量绑定到 esi 寄存器(& 表示早期破坏)

输入操作数:

  • "1" (s):输入字符串 s 使用与操作数1相同的约束(即 esi 寄存器)
  • "0" (c):输入字符 c 使用与操作数0相同的约束(即 eax 寄存器)

2.6. 第七段:函数返回

c 复制代码
    return __res;
}
  • 返回查找到的字符指针,如果未找到则返回 NULL

3. 函数工作流程图

相等 不相等 是0,字符串结束 不是0 开始strchr 备份字符c到ah lodsb加载字符到al 比较al和ah 跳转到成功处理 测试al是否为0 设置d0=1查找失败 继续循环 返回NULL 调整指针位置 返回找到的指针

4. 寄存器使用说明

寄存器 用途
eax (al/ah) al 存储当前字符,ah 存储目标字符
esi 字符串扫描指针
__res 结果指针(通过 eax 返回)

5. 汇编指令详解

  • lodsb:从 [esi] 加载字节到 al,同时 esi 自动加1
  • cmpb:比较两个字节
  • testb:测试字节值(常用于检测是否为0)
  • je/jne:条件跳转(相等/不相等)
  • movb/movl:移动字节/双字
  • decl:递减

6. 函数功能总结

主要功能 :在字符串 s 中查找字符 c 的第一次出现位置

返回值

  • 成功:指向找到字符的指针
  • 失败:NULL 指针

特点

  • 使用内联汇编实现,效率高
  • 直接操作寄存器,避免函数调用开销
  • 使用 lodsb 指令高效遍历字符串
  • 正确处理字符串终止符检测

这个实现展示了如何用汇编语言高效实现字符串操作,特别适合在内核等性能敏感的场景中使用。

相关推荐
开心大爆炸9 小时前
xrdp 连接 登录对话框输入密码后闪退
linux·运维·服务器
oushaojun29 小时前
大厂 C++ 面试:深度剖析 Linux Signal 信号机制(转)
linux
苏生Susheng10 小时前
【软件实施】Linux系统Shell脚本教程
linux·运维·服务器·chrome·spring boot·学习·实施
Ruiery10 小时前
Linux 6.6内核 IOMMU 深度解析(七):DMA API 与 IOMMU 集成 — 从 dma_map_single 到 iommu_map
linux·运维·服务器
分支预测失败10 小时前
RISC-V AIA 中断架构实战:从 PLIC 到 APLIC 与 IMSIC 的迁移
linux·后端
GeW10 小时前
RHCE学习拿证计划:锁定核心考点,实现备考效率最大化
linux
snow@li11 小时前
服务器运维:Alibaba Cloud Linux 4 LTS 64位 根目录全景深度解析文章
linux·运维·服务器
苏生Susheng11 小时前
【软件实施】Linux企业运维常用命令手册
java·linux·运维·服务器·springboot·springcloud·软件实施
额额额对了11 小时前
Linux 进程间通信(IPC)核心机制:消息队列、共享内存与信号量详解
linux·网络·网络协议
zx_7414848112 小时前
【Linux入门】Linux 安装:VMware Workstation Pro 安装 CentOS 7 保姆级图文教程
linux·centos