Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 汇编:在函数中访问同一寄存器的四字、双字和字节数量_C_Assembly_X86 64 - Fatal编程技术网

C 汇编:在函数中访问同一寄存器的四字、双字和字节数量

C 汇编:在函数中访问同一寄存器的四字、双字和字节数量,c,assembly,x86-64,C,Assembly,X86 64,我有一些从C生成的汇编代码,我正试图理解这些代码。有一部分我就是不明白: movslq %edx,%rcx movzbl (%rdi,%rcx,1),%ecx test %cl,%cl 没有意义的是,%rcx、%ecx和%cl都在同一寄存器中(分别是四字、双字和字节)。一个数据类型如何在同一个函数中访问这三个函数 使用char*不太可能以这种方式访问%ecx,同样,使用int*也不太可能访问%cl。我根本不知道什么数据类型可以存储在%rcxre:你的评论:你可以告诉它是一个字节

我有一些从C生成的汇编代码,我正试图理解这些代码。有一部分我就是不明白:

movslq   %edx,%rcx
movzbl   (%rdi,%rcx,1),%ecx
test     %cl,%cl
没有意义的是,
%rcx
%ecx
%cl
都在同一寄存器中(分别是四字、双字和字节)。一个数据类型如何在同一个函数中访问这三个函数


使用
char*
不太可能以这种方式访问
%ecx
,同样,使用
int*
也不太可能访问
%cl
。我根本不知道什么数据类型可以存储在
%rcx

re:你的评论:你可以告诉它是一个字节数组,因为它按1缩放
%rcx

就像迈克尔在评论中说的,这是在做

int func(char *array /* rdi */, int pos /* ecx */)
{
    if (array[pos]) ...;

    // or maybe
    int  tmpi = array[pos];
    char tmpc = tmpi;
    if (tmpc) ...;
}
ecx在用作有效地址中的偏移量之前,必须将符号扩展到64位。如果未签名,则仍需要零扩展(例如,
mov%ecx,%ecx
)。当在寄存器中传递的参数小于64位时,ABI不保证寄存器的上32位为零或符号扩展

一般来说,最好至少写入32b的寄存器,以避免对某些CPU上先前内容的错误依赖。只有Intel P6/SnB系列CPU单独跟踪整数寄存器(如果您在写入
%cl
后执行类似读取
%ecx
的操作,则插入额外的uop以将其与旧内容合并)


因此,编译器使用零扩展的
movzbl
加载而不是
mov(%rdi,%rcx,1),%cl
来发出代码是完全合理的。它可能在Silvermont和AMD上运行得更快。(还有P4.对旧CPU的优化确实在编译器源代码中存在…

re:您的评论:您可以判断它是一个字节数组,因为它正在按1缩放
%rcx

就像迈克尔在评论中说的,这是在做

int func(char *array /* rdi */, int pos /* ecx */)
{
    if (array[pos]) ...;

    // or maybe
    int  tmpi = array[pos];
    char tmpc = tmpi;
    if (tmpc) ...;
}
ecx在用作有效地址中的偏移量之前,必须将符号扩展到64位。如果未签名,则仍需要零扩展(例如,
mov%ecx,%ecx
)。当在寄存器中传递的参数小于64位时,ABI不保证寄存器的上32位为零或符号扩展

一般来说,最好至少写入32b的寄存器,以避免对某些CPU上先前内容的错误依赖。只有Intel P6/SnB系列CPU单独跟踪整数寄存器(如果您在写入
%cl
后执行类似读取
%ecx
的操作,则插入额外的uop以将其与旧内容合并)


因此,编译器使用零扩展的
movzbl
加载而不是
mov(%rdi,%rcx,1),%cl
来发出代码是完全合理的。它可能在Silvermont和AMD上运行得更快。(还有P4.对旧CPU的优化确实在编译器源代码中存在…

“我根本不知道%rcx中可以存储什么数据类型。”。您发布的代码使用AT&T语法,因此操作数顺序为
src,dest
。因此,
edx
中的值被符号扩展到
rcx
,然后
rcx
被用作字节数组的索引,从该数组加载一个值,并将其零扩展到
ecx
,最后检查加载的字节是否为零。如何将零扩展到64位数据类型的前32位?正如我所说,这意味着
int*
,但是如果不使用一些按位移位运算符,就无法检查加载的字节。“我根本不知道%rcx中可以存储什么数据类型”。您发布的代码使用AT&T语法,因此操作数顺序为
src,dest
。因此,
edx
中的值被符号扩展到
rcx
,然后
rcx
被用作字节数组的索引,从该数组加载一个值,并将其零扩展到
ecx
,最后检查加载的字节是否为零。如何将零扩展到64位数据类型的前32位?正如我所说,这意味着
int*
,但是如果不使用一些按位移位运算符,就无法检查加载的字节。