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 指令高效遍历字符串
  • 正确处理字符串终止符检测

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

相关推荐
南棱笑笑生16 小时前
20251106给荣品RD-RK3588-MID开发板跑Rockchip的原厂Android13系统时禁止锁屏+永不休眠
linux·运维·服务器·rockchip
赖small强16 小时前
Linux 优先级反转问题详解与处理方案
linux·优先级反转·优先级继承·缩短临界区
wdfk_prog17 小时前
[Linux]学习笔记系列 -- [kernel][time]timekeeping
linux·笔记·学习
yuanManGan17 小时前
走进Linux的世界:冯诺依曼体系结构
linux
小白银子17 小时前
零基础从头教学Linux(Day 60)
linux·数据库·mysql·oracle
new_daimond17 小时前
Linux 服务器内存监控与优化指南
linux·服务器·chrome
一介草民丶17 小时前
Linux | Mongodb 6 离线安装
linux·运维·mongodb
赖small强17 小时前
Linux 线程相关结构对照表与关系图
linux·thread_info·task_struct·thread_struct
Justin_1917 小时前
部署zabbix
linux·centos·zabbix
STUPID MAN18 小时前
Linux使用tomcat发布vue打包的dist或html
linux·vue.js·tomcat·html