由直接C生成的特殊指令序列;如果;缺乏条件
我试图在gcc(Ubuntu/Linaro4.6.3-1ubuntu5)4.6.3下为x86-64调试一些简单的C代码。代码是用由直接C生成的特殊指令序列;如果;缺乏条件,c,C,我试图在gcc(Ubuntu/Linaro4.6.3-1ubuntu5)4.6.3下为x86-64调试一些简单的C代码。代码是用CFLAGS+=-std=c99-g-Wall-O0构建的 #include <errno.h> #include <stdio.h> #include <string.h> #pragma pack(1) int main (int argc, char **argv) { FILE *f = fopen (
CFLAGS+=-std=c99-g-Wall-O0构建的
#include <errno.h>
#include <stdio.h>
#include <string.h>
#pragma pack(1)
int main (int argc, char **argv)
{
FILE *f = fopen ("the_file", "r"); /* error checking removed for clarity */
struct {
short len;
short itm [4];
char nul;
} f00f;
int n = fread (&f00f, 1, sizeof f00f, f);
if (f00f.nul ||
f00f.len != 0x900 ||
f00f.itm [0] != 0xf00f ||
f00f.itm [1] != 0xf00f ||
f00f.itm [2] != 0xf00f ||
f00f.itm [3] != 0xf00f)
{
fprintf (stderr, "bitfile_hdr F00F data err:\n"
"\tNUL: 0x%x\n"
"\tlen: 0x%hx should be 0x900\n"
"\tf00f: 0x%hx\n"
"\tf00f: 0x%hx\n"
"\tf00f: 0x%hx\n"
"\tf00f: 0x%hx\n"
, f00f.nul, f00f.len,
f00f.itm[0], f00f.itm[1], f00f.itm[2], f00f.itm[3]
);
return 1;
}
return 0;
}
在gdb
下运行它并检查结构也会显示正确的数据
(gdb) p /x f00f
$1 = {len = 0x900, itm = {0xf00f, 0xf00f, 0xf00f, 0xf00f}, nul = 0x0}
由于这没有意义,我检查了gdb内部的指令,以揭示编码病理学。与不起作用的if
对应的说明如下:
0x0000000000400736 <+210>: movzwl -0x38(%rbp),%eax
0x000000000040073a <+214>: movswl %ax,%r8d
0x000000000040073e <+218>: movzwl -0x3a(%rbp),%eax
0x0000000000400742 <+222>: movswl %ax,%edi
0x0000000000400745 <+225>: movzwl -0x3c(%rbp),%eax
0x0000000000400749 <+229>: movswl %ax,%r9d
0x000000000040074d <+233>: movzwl -0x3e(%rbp),%eax
0x0000000000400751 <+237>: movswl %ax,%r10d
0x0000000000400755 <+241>: movzwl -0x40(%rbp),%eax
0x0000000000400759 <+245>: movswl %ax,%ecx
0x000000000040075c <+248>: movzbl -0x36(%rbp),%eax
0x0000000000400760 <+252>: movsbl %al,%edx
0x0000000000400763 <+255>: mov $0x4008d8,%esi
0x0000000000400768 <+260>: mov 0x2008d1(%rip),%rax # 0x601040 <stderr@@GLIBC_2.2.5>
0x000000000040076f <+267>: mov %r8d,0x8(%rsp)
0x0000000000400774 <+272>: mov %edi,(%rsp)
0x0000000000400777 <+275>: mov %r10d,%r8d
0x000000000040077a <+278>: mov %rax,%rdi
0x000000000040077d <+281>: mov $0x0,%eax
0x0000000000400782 <+286>: callq 0x400550 <fprintf@plt>
0x0000000000400787 <+291>: mov $0x6,%eax
0x000000000040078c <+296>: add $0x50,%rsp
0x0000000000400790 <+300>: pop %rbx
0x0000000000400791 <+301>: pop %r12
0x0000000000400793 <+303>: pop %rbp
0x0000000000400794 <+304>: retq
0x0000000000400736:movzwl-0x38(%rbp),%eax
0x000000000040073a:movswl%ax,%r8d
0x000000000040073e:movzwl-0x3a(%rbp),%eax
0x0000000000400742:movswl%ax,%edi
0x0000000000400745:movzwl-0x3c(%rbp),%eax
0x0000000000400749:movswl%ax,%r9d
0x000000000040074d:movzwl-0x3e(%rbp),%eax
0x0000000000400751:movswl%ax,%r10d
0x0000000000400755:movzwl-0x40(%rbp),%eax
0x0000000000400759:movswl%ax,%ecx
0x000000000040075c:movzbl-0x36(%rbp),%eax
0x0000000000400760:movsbl%al,%edx
0x0000000000400763:mov$0x4008d8,%esi
0x0000000000400768:mov 0x2008d1(%rip),%rax#0x601040
0x000000000040076f:mov%r8d,0x8(%rsp)
0x0000000000400774:mov%edi,(%rsp)
0x0000000000400777:mov%r10d,%r8d
0x000000000040077a:mov%rax,%rdi
0x000000000040077d:mov$0x0,%eax
0x0000000000400782:callq 0x400550
0x0000000000400787:mov$0x6,%eax
0x000000000040078c:添加$0x50,%rsp
0x0000000000400790:弹出%rbx
0x0000000000400791:弹出%r12
0x0000000000400793:弹出%rbp
0x0000000000400794:retq
很难看出这是如何实现有条件的
有人知道这(mis)为什么会这样吗?可能在您的平台上,short
是16位宽。因此,任何short
都不能等于0xf00f
和条件f00f.itm[0]!=0xf00f
始终为真。编译器进行了相应的优化
在struct f00f
的定义中,您可能指的是unsigned short
,但这当然只是修复它的一种方法。您也可以将f00f.itm[0]
与(short)0xf00f
进行比较,但如果您的意思是f00f.itm[i]
与0xf00f
进行比较,您肯定应该在定义中使用无符号short
代码>将值-4081指定给val
你会被整数提升规则击中
f00f.itm [0] != 0xf00f
将f00f.itm[0]
中的短字符转换为int,即-4081。0xf00f作为int是61455,这两个值不相等。由于在打印值时(通过使用%hx
),该值会转换为无符号的短字符,因此在输出中看不到该问题
在结构中使用无符号值,因为您似乎将这些值视为无符号:
struct {
unsigned short len;
unsigned short itm [4];
char nul;
} f00f;
此示例程序可能会让您更好地了解正在发生的事情:
#include <stdio.h>
int main(int argc,char *arga[])
{
short x = 0xf00f;
int y = 0xf00f;
printf("x = 0x%hx y = 0x%x\n", x, y);
printf("x = %d y = %d\n", x, y);
printf("x==y: %d\n", x == y);
return 0;
}
#包括
int main(int argc,char*arga[])
{
短x=0xf00f;
int y=0xf00f;
printf(“x=0x%hx y=0x%x\n”,x,y);
printf(“x=%d y=%d\n”,x,y);
printf(“x==y:%d\n”,x==y);
返回0;
}
与您的问题无关,但不会fread(&f00f,1,sizeof f00f,f)代码>使fread(&f00f,sizeof f00f,1,f)更有意义代码>?根据我的文档,这将确保您不会阅读半个结构。该程序集是否紧跟在fread
调用之后?@PascalCuoq:我认为fread
的文档没有那么有用。我通常希望验证字节数,而不是项目数。这就是为什么我总是“把它转过来”,以便能够报告一个简短的阅读有多短。在一个无关的注释上,请清理您的代码conventions@aschepler:是的,逻辑上是这样。在未桥接的代码中,检查fread
读取的字节是否足以填充结构。我把它取出来是因为a)它总是有效的,b)为了简化问题。Short是16位,但0xf00f也是如此。@wallyk0xf00f
适合16位无符号整数类型,但它不适合16位有符号整数类型。在gcc中,-Wextra
将警告此类比较:警告:由于数据类型[-Wtype limits]的范围有限,比较始终为真。
是的。这就是问题所在。谢谢是的,这就是问题所在。我只是验证了一下,但既然帕斯卡先回答了,他就得到了荣誉。
#include <stdio.h>
int main(int argc,char *arga[])
{
short x = 0xf00f;
int y = 0xf00f;
printf("x = 0x%hx y = 0x%x\n", x, y);
printf("x = %d y = %d\n", x, y);
printf("x==y: %d\n", x == y);
return 0;
}