我是汇编新手,有一个简单的 C 程序将字符串打印到标准输出。在汇编中,这转换为 main
调用 _IO_Puts
。 _IO_puts
的实现如下摘自:https://code.woboq.org/userspace/glibc/libio/ioputs.c.html如下所示。
int
_IO_puts (const char *str)
{
int result = EOF;
size_t len = strlen (str);
_IO_acquire_lock (stdout);
if ((_IO_vtable_offset (stdout) != 0
|| _IO_fwide (stdout, -1) == -1)
&& _IO_sputn (stdout, str, len) == len
&& _IO_putc_unlocked ('\n', stdout) != EOF)
result = MIN (INT_MAX, len + 1);
_IO_release_lock (stdout);
return result;
}
我无法弄清楚为什么在模拟 MIPS 处理器上动态指令的数量会随着字符串长度的增加而变化,有时甚至会减少?
最佳答案
如评论中所述,glibc _IO_sputn
涉及执行 strlen 和该大小的 memcpy。
MIPS 上的 glibc strlen 使用一次检查 4 个字节的纯 C bithack。 (与大多数其他具有手写 asm 的 ISA 不同)。 Why does glibc's strlen need to be so complicated to run quickly? .它非常不简单,它的启动策略取决于字符串开头的对齐方式。
这里更相关,在一个字的第 4 个字节找到终止 0
字节,而不是在下一个字的第 1 个字节,也可能需要更少的指令。 (或者对于 MIPS64,第 8 名与第 1 名)。所以这可能就是您看到动态指令计数的非单调缩放的原因。
memcpy
也将为 4(或 8)字节的倍数采用更少的指令,并且它通过对大小的分支以及 src 和 dst 的可能对齐来选择策略。 (MIPS32/64r6 之前的 MIPS 不保证有效的未对齐存储)。因此,对不涉及刷新缓冲区的 stdio 函数的顺序调用可能导致 stdout 缓冲区的不同目标对齐。
关于c - _IO_puts 和动态指令计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69029646/