先来一个小插曲

#define TO_STRING(x) #x

int main() {
    const char *str = TO_STRING(Hello, World!);
    printf("%s\n", str); // 输出 "Hello, World!"
    return 0;
}

printf 接受一个指针, #x 相当于一个地址

在头文件里面, 下面定义一个函数(宏的方式)

#define read_csr(csr)                        \
({                                \
    register unsigned long __v;                \
    __asm__ __volatile__ ("csrr %0, " #csr            \
                  : "=r" (__v) :            \
                  : "memory");            \
    __v;                            \
})

调用这个函数

void sbi_main(void)
{
    unsigned long val; //汇编的函数返回值
    val = read_csr(mstatus); //给函数传递参数,不是string
    write_csr(mstatus, val);
}

内敛的汇编的基本格式

asm ( assembler template 
    : output operands                  /* 可选 ,输出参数*/
    : input operands                   /* 可选 ,输入参数*/
    : clobbered registers              /* 可选 ,可能修改的寄存器,破坏性描述符,就是对环境的影响*/
);

举个例子01:

#include <stdio.h>

int main() {
    int a = 10, b = 20;
    int result;

    __asm__ (
        "add %0, %1, %2\n\t"
        : "=r" (result)
        : "r" (a), "r" (b)
    );

    printf("Result: %d\n", result);
    return 0;
}

解释:
=r 表示将结果存储在一个通用寄存器中
"r" (a), "r" (b):这是输入操作数部分。r 表示将变量 a 和 b 的值加载到通用寄存器中
类似c语言的字段类型,汇编也有一些参数说明(约束字符)
比如上面的r就是一种, 输入放到通用寄存器中

通用约束字符
r:表示操作数应放在一个通用寄存器中。
m:表示操作数应放在内存中。
i:表示操作数是一个立即数(常量)。
g:表示操作数可以是一个通用寄存器、内存或立即数。
0, 1, 2, ...:表示操作数与第几个操作数相同。
破坏描述符
"cc":表示汇编代码会修改条件码寄存器(condition code register)。
"memory":表示汇编代码会修改内存。
"r0", "r1", ...:表示汇编代码会修改特定的寄存器(特定于目标架构)。


putao
8 声望3 粉丝

推动世界向前发展,改善民生。