2015-01-16 117 views
0

我很难理解Perl的命令print是如何解释十六进制值的。我正在使用一个只有8行的简单程序来演示我的问题。与gdb下面的代码会解释我的问题详细:命令行输入到C程序中(使用'print'命令的Perl)

[email protected]:~/Desktop$ gcc -g code.c 
[email protected]:~/Desktop$ gdb -q ./a.out 
Reading symbols from ./a.out...done. 
(gdb) list 
1 #include <stdio.h> 
2 
3 int main(int argc, char* argv[]) 
4 { 
5  int i; 
6  for (i =0; i<argc; ++i) 
7   printf ("%p\n", argv[i]); 
8  return 0; 
9 } 
(gdb) break 8 
Breakpoint 1 at 0x40057a: file code.c, line 8. 
(gdb) run $(perl -e 'print "\xdd\xcc\xbb\xaa"') $(perl -e 'print "\xcc\xdd\xee\xff"') 
Starting program: /home/anil/Desktop/a.out $(perl -e 'print "\xdd\xcc\xbb\xaa"') $(perl -e 'print "\xcc\xdd\xee\xff"') 
0x7fffffffe35d 
0x7fffffffe376 
0x7fffffffe37b 

Breakpoint 1, main (argc=3, argv=0x7fffffffdfe8) at code.c:8 
8  return 0; 
(gdb) x/2x argv[1] 
0x7fffffffe376: 0xaabbccdd 0xeeddcc00 

在上面行我已经使用gdb调试程序。作为命令行参数,我已经传递了两个(十六进制)参数(不包括程序本身的名称):\xdd\xcc\xbb\xaa\xcc\xdd\xee\xff。由于小端架构,这些参数应该被解释为0xaabbccdd0xffeeddcc,但正如您所看到的,上面显示的调试的最后一行显示为0xaabbccdd0xeeddcc00。这是为什么?我在想什么?这也发生在其他一些论点。我请求你帮助我。 (2^32>0xffeeddcc)。其中,我不知道是否还有任何联系。

+0

Endianness是如何存储多字节标量值(如int)的方式。你程序的参数是字符串。 (如果Little-Endian机器打印出“lleHow o!dlr”会不会很愚蠢?) –

+0

形式\ x ## \ x ## \ x ## \ x ##的输入显示它们包含十六进制值,因此需要对它们进行不同的解释。 – aniliitb10

回答

2

命令行参数是NUL终止的字符串。

参数argv[1]是一个指向NUL终止字符串的第一个字符的指针。

7FFFFFFFE376 DD CC BB AA 00 

argv[2]是一个指针指向一个NUL结尾的字符串的第一个字符。

7FFFFFFFE37B CC DD EE FF 00 

如果你注意,你会注意到它们恰好在记忆中一个接一个的位置。

7FFFFFFFE376 DD CC BB AA 00 CC DD EE FF 00 

您要求打印(32位)整数开始argv[1]

7FFFFFFFE376 DD CC BB AA 00 CC DD EE FF 00 
       ----------- ----------- 
       0xAABBCCDD 0xEEDDCC00 

x/2x是正确的,你会需要使用

perl -e'print "\xdd\xcc\xbb\xaa\xcc\xdd\xee\xff"' 
    -or- 
perl -e'print pack "i*", 0xaabbccdd, 0xffeeddcc' 

对于参数你通过了,你需要使用

(gdb) x argv[1] 
0x3e080048cbd: 0xaabbccdd 
(gdb) x argv[2] 
0x3e080048cc2: 0xffeeddcc 
+0

是的,我知道为什么其他论据也有类似的结果。感谢您的详细解答。 – aniliitb10

+0

如果运行命令如下: 'run $(perl -e'print'\ xaa \ xbb \ x00 \ xcc'')$(perl -e'print“\ xaa \ xbb \ xcc \ x00”') $(perl -e'print'\ xaa \ x00 \ xdd \ xcc'')' x/15xb argv [1]上的预期结果是:0xaa 0xbb 0x00 0xcc 0x00 0xaa \t 0xbb 0xcc 0x00 0x00 0xaa 0x00 0xdd 0xcc 0x00“,其中第5,第10和第15个”0x00“应该属于空终结符,但实际的输出是:0xaa 0xbb 0xcc 0x00 0xaa 0xbb 0xcc 0x00 0xaa \t 0xdd \t 0xcc \t 0x00 0x58 0x44 0x47在我认为0x00 '的输入已被忽略,只考虑了对应于空终止符的'0x00'。任何解释? – aniliitb10

2

通过将字符串作为数字打印,可能会让您感到困惑。在little-endian体系结构中,在诸如0xDDCCBBAA的四字节值中,从起始地址开始,字节编号为从左到右

那么让我们来看看你的调试器命令的输出:

(gdb) x/2x argv[1] 
0x7fffffffe376: 0xaabbccdd 0xeeddcc00 

望着按字节该字节,这将是:

0x7fffffffe376: dd 
0x7fffffffe377: cc 
0x7fffffffe378: bb 
0x7fffffffe379: aa 

0x7fffffffe37a: 00 # This NUL terminates argv[1] 
0x7fffffffe37b: cc # This address corresponds to argv[2] 
0x7fffffffe37c: dd 
0x7fffffffe37d: ee 

这并不意外,不是吗?

您可能需要使用像这样以十六进制显示参数:

x/8bx argv[1] 

(它会显示 b ytes在他X adecimal)

+0

感谢您指出错误,错误地忽略了NUL终结者。 – aniliitb10

+0

如果运行命令如下: 'run $(perl -e'print'\ xaa \ xbb \ x00 \ xcc'')$(perl -e'print“\ xaa \ xbb \ xcc \ x00”') $(perl -e'print'\ xaa \ x00 \ xdd \ xcc'')' 'x/15xb argv [1]'上的预期结果是:0xaa 0xbb 0x00 0xcc 0x00 0xaa \t 0xbb 0xcc 0x00 0x00 0xaa 0x00 0xdd 0xcc 0x00'其中第5,第10和第15'0x00'应该属于空终结符,但实际输出是:0xaa 0xbb 0xcc 0x00 0xaa 0xbb 0xcc 0x00 0xaa \t 0xdd \t 0xcc \t 0x00 0x58 0x44 0x47'它看起来输入的0x00被忽略,只考虑对应于空终止符的0x00。任何解释? – aniliitb10

+1

@ aniliitb10:bash字符串不能包含NUL。或者,更准确地说,bash字符串总是以NUL结尾。因此'$(printf'\ xaa \ xbb \ x00 \ xcc')'(与您的perl打印语句相同)的结果实际上是两个字符'\ xaa \ xbb'的NUL终止字符串。 – rici