栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

GCC:内联汇编中的putchar(char)

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

GCC:内联汇编中的putchar(char)

使用GNU C内联asm时,请 使用约束来告诉编译器您想要的东西 ,而不是使用asm模板中的指令“手动”进行。

对于

writechar
readchar
,我们只需要
"syscall"
为模板,用约束来设置所有寄存器输入(与所指向
char
的内存的
write(2)
系统调用),根据X86-64的Linux系统调用约定(这非常密切与System V ABI的函数调用约定匹配)。

这也使得避免编译器可能保留值的红色区域(比RSP低128个字节)变得容易。您一定不能从内联asm破坏它(因此

push
/
pop
除非
sub rsp,128
首先使用,否则是不可用的:请参见在C++内联asm中使用基本指针寄存器,以及有关GNUC内联asm的许多有用链接),并且无法告诉编译器您破坏它。您可以使用构建
-mno-redzone
,但是在这种情况下,输入/输出操作数要好得多。


我不愿把这些

putchar
getchar
。如果要实现自己的不支持缓冲的stdio,则可以执行此操作,但是某些功能 需要
输入缓冲才能正确实现。例如,
scanf
必须检查字符以查看它们是否与格式字符串匹配,如果不匹配则将其保留为“未读”。输出缓冲是可选的。您 可能会 认为_可以_使用创建私有缓冲区及其功能的函数
write()
或直接
write()
输入指针的函数完全实现stdio 。

writechar()

int writechar(char my_char){    int retval;  // sys_write uses ssize_t, but we only pass len=1      // so the return value is either 1 on success or  -1..-4095 for error      // and thus fits in int    asm volatile("syscall  #dummy arg picked %[dummy]n"         : "=a" (retval)                    : "D"(1),         // RDI = fd=stdout"S"(&my_char),  // RSI = buf"d"(1)          // RDX = length, [dummy]"m" (my_char) // dummy memory input, otherwise compiler doesn't store the arg                  : "rcx", "r11"  // clobbered by syscall     );    // It doesn't matter what addressing mode "m"(my_char) picks,    // as long as it refers to the same memory as &my_char so the compiler actually does a store    return retval;}

在Godbolt编译器资源管理器上,这可以使用gcc
-O3
非常有效地进行编译。

writechar:    movb    %dil, -4(%rsp)        # store my_char into the red-zone    movl    $1, %edi    leaq    -4(%rsp), %rsi    movl    %edi, %edx # optimize because fd = len    syscall    # dummy arg picked -4(%rsp)    ret

@ NRZ的测试

main
内联也
更有效地比在回答不安全(红色区域重挫)版本,服用的事实优势,
syscall
让大部分寄存器未修改所以它可以只设置一次即可。

main:    movl    $97, %r8d # my_char = 'a'    leaq    -1(%rsp), %rsi       # rsi = &my_char    movl    $1, %edx  # len.L6:     # do {    movb    %r8b, -1(%rsp)       # store the char into the buffer    movl    %edx, %edi# silly compiler doesn't hoist this out of the loop    syscall  #dummy arg picked -1(%rsp)    addl    $1, %r8d    cmpb    $123, %r8b    jne     .L6     # } while(++my_char < 'z'+1)    movb    $10, -1(%rsp)    syscall  #dummy arg picked -1(%rsp)    xorl    %eax, %eax         # return 0    ret

readchar(),以相同的方式完成:

int readchar(void){    int retval;    unsigned char my_char;    asm volatile("syscall  #dummy arg picked %[dummy]n"                  : "=a" (retval)          ,[dummy]"=m" (my_char) // tell the compiler the asm dereferences &my_char                  : "D"(0),         // RDI = fd=stdin"S" (&my_char), // RDI = buf"d"(1)          // RDX = length         : "rcx", "r11"  // clobbered by syscall     );    if (retval < 0)   // -1 .. -4095 are -errno values        return retval;    return my_char;   // else a 0..255 char / byte}

呼叫者可以通过检查来检查错误

c < 0



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/402666.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号