C- 内联汇编实现puts函数

使用内联汇编实现的puts()函数如下:

#define SYS_WRITE 1

#define CALL2(n) "movq $"#n", %%rax\n"
#define CALL(n) CALL2(n)

int puts(char *s) {
    
    
    long n = strlen(s);
    long r;
    asm(CALL(SYS_WRITE)
       "movq $1, %%rdi\n"
       "movq %1, %%rsi\n"
       "movq %2, %%rdx\n"
       "syscall\n"
       "movq %%rax, %0\n"
       : "=r"(r)
       : "r"(s), "r"(n)
       : "%rax", "%rdi", "%rsi", "%rdx");
    return (int)r;
}

这段代码提供了一个简化版的puts函数,它使用内联汇编在Linux上直接执行write系统调用以输出字符串到标准输出。我们将逐步详细分析这个函数:

  1. 函数定义和变量初始化:
int puts(char *s) {
    
    
    long n = strlen(s);
    long r;

这定义了一个puts函数,它接收一个字符串s作为参数。函数内部首先计算s的长度,并将结果存储在变量n中。

  1. 内联汇编部分:

这是一个用GCC扩展的语法书写的内联汇编代码块。它直接使用x86-64架构上的汇编指令来调用Linux的系统调用。

    asm(CALL(SYS_WRITE)

这部分引用一个宏或外部定义CALL(SYS_WRITE),它应该解析为对write系统调用的编号。但在这段代码中,我们没有看到这些宏的定义。

接下来的汇编指令是为write系统调用设置参数:

  • "movq $1, %%rdi\n": 将文件描述符1(标准输出)设置为第一个参数。

  • "movq %1, %%rsi\n": 将字符串的地址设置为第二个参数。

  • "movq %2, %%rdx\n": 将字符串长度设置为第三个参数。

接着是实际的系统调用指令:

  • "syscall\n": 执行系统调用。

最后,系统调用的返回值(在rax寄存器中)被移动到变量r中。

  1. 输入输出和汇编代码的占位符:
  • : "=r"(r): 输出部分,指示r变量接收一个寄存器的值(特别是rax,即系统调用的返回值)。

  • : "r"(s), "r"(n): 输入部分,指定sn两个变量分别传递给rsirdx寄存器。

  • : "%rax", "%rdi", "%rsi", "%rdx": Clobbered register list,告诉编译器这些寄存器的值在汇编代码块中已被修改。

  1. 返回值:
    return (int)r;
}

该函数最后返回写入的字节数,或在出错时返回一个负值。

综上所述,这个puts函数使用内联汇编直接与Linux内核进行交互,将字符串s写入到标准输出。

猜你喜欢

转载自blog.csdn.net/weixin_43844521/article/details/133365414
C-