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

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

相关推荐
tianyuanwo3 小时前
虚拟机监控全攻略:从基础到云原生实战
linux·云原生·虚机监控
别或许3 小时前
在centos系统下,安装MYSQL
linux·mysql·centos
丁丁丁梦涛3 小时前
CentOS修改MySQL数据目录后重启失败的问题及解决方案
linux·mysql·centos
黑马金牌编程3 小时前
Jenkins的Linux与window部署方式
linux·运维·windows·jenkins·持续集成·cicd
web安全工具库3 小时前
告别刀耕火种:用 Makefile 自动化 C 语言项目编译
linux·运维·c语言·开发语言·数据库·算法·自动化
DechinPhy4 小时前
Ubuntu挂载新硬盘
linux·运维·服务器·ubuntu
lht6319356124 小时前
Ubuntu Server 系统安装图形界面远程工具(RDP)
linux·运维·ubuntu
云计算练习生4 小时前
linux shell编程实战 02 变量与交互式输入
linux·运维·shell编程·shell 变量
Dovis(誓平步青云)4 小时前
《简易制作 Linux Shell:详细分析原理、设计与实践》
linux·运维·服务器