详解从高低地址和高未有起初驾驭,Linux中hexdump命令用法

hexdump命令一般用来查看”二进制”文件的十六进制编码,从手册上查看,其查看的内容还要很多,诸如:ascii,
decimal, hexadecimal, octal

一、字节序定义

参数:

字节序,顾名思义字节的顺序,再多说两句就是大于一个字节类型的数据在内存中的存放顺序(一个字节的数据当然就无需谈顺序的问题了)。

hexdump [-bcCdovx] [-e format_string] [-f format_file] [-n
length] [-s skip] file

其实大部分人在实际的开发中都很少会直接和字节序打交道。唯有在跨平台以及网络程序中字节序才是一个应该被考虑的问题。

示例:

在所有的介绍字节序的文章中都会提到字节序分为两类:Big-Endian和Little-Endian。引用标准的Big-Endian和Little-Endian的定义如下:
a)
Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
b)
Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
c) 网络字节序:4个字节的32
bit值以下面的次序传输:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。这种传输次序称作大端字节序。由于
TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。比如,以太网头部中2字节的“以太网帧类型”,表示后面数据的类型。对于ARP请求或应答的以太网帧类型来说,在网络传输时,发送的顺序是0x08,0x06。在内存中的映象如下图所示:

新增一个文本文件,在test 文本中添加如下内容:

栈底 (高地址)

0x06 — 低位 

[root@node61 test]# cat test 
abcde
ABCDE

0x08 — 高位

栈顶 (低地址)
该字段的值为0x0806。按照大端方式存放在内存中。

二、高/低地址与高低字节

首先我们要知道我们C程序映像中内存的空间布局情况:在《C专家编程》中或者《Unix环境高级编程》中有关于内存空间布局情况的说明,大致如下图:
———————– 最高内存地址 0xffffffff
 | 栈底
 .
 .              栈
 .

1)最简单的查看

  栈顶

 |
 |
\|/

NULL (空洞)

/|\
 |

[root@node61 test]# hexdump test 
0000000 6261 6463 0a65 4241 4443 0a45 
000000c

 |

第一列:表示文件文件偏移量

                堆

未初始化的数据
—————-(统称数据段)

第二列:已两个字节为一组的十六进制

初始化的数据

正文段(代码段)
———————– 最低内存地址 0x00000000

以上图为例如果我们在栈上分配一个unsigned
char buf[4],那么这个数组变量在栈上是如何布局的呢[注1]?看下图:

通过上面的输出,翻译成文本为:badc0aeBADC0aE(注意:在Linux中换行符\n
的十六进制为0a,在windows中,换行为\r\n的十六进制编码为:0d
0a),另:下图为ASC码表对应的进制编码

栈底 (高地址)

buf[3]
buf[2]
buf[1]

图片 1

buf[0]

栈顶 (低地址)

现在我们弄清了高低地址,接着来弄清高/低字节,如果我们有一个32位无符号整型0x12345678(呵呵,恰好是把上面的那4个字节buf看成一个整型),那么高位是什么,低位又是什么呢?其实很简单。在十进制中我们都说靠左边的是高位,靠右边的是低位,在其他进制也是如此。就拿
0x12345678来说,从高位到低位的字节依次是0x12、0x34、0x56和0x78。

高低地址和高低字节都弄清了。我们再来回顾一下Big-Endian和Little-Endian的定义,并用图示说明两种字节序:
以unsigned int value =
0x12345678为例,分别看看在两种字节序下其存储情况,我们可以用unsigned
char buf[4]来表示value:
Big-Endian: 低地址存放高位,如下图:

细心的读者可能已经发现了,为什么翻译成文本成倒序了呢?文本中的内容不是:abcde
ABCDE 吗?

栈底 (高地址)

buf[3] (0x78) — 低位
buf[2] (0x56)
buf[1] (0x34)

其实这是X86的CPU架构所致,又进行了一番研究:字节序

buf[0] (0x12) — 高位

栈顶 (低地址)

Little-Endian:
低地址存放低位,如下图:

字节序:其实就是字节的顺序,这里是针对大于两个字节来说,一个字节就没有排序而言了,然而,在大部分的工作中,我们都很少直接和字节序打交道。

栈底 (高地址)

buf[3] (0x12) — 高位
buf[2] (0x34)
buf[1] (0x56)

字节序分类两类:Big-Endian 和Little-Endian

buf[0] (0x78) — 低位

栈顶 (低地址)

在现有的平台上Intel的X86采用的是Little-Endian,而像Sun的SPARC采用的就是Big-Endian。

三、例子

嵌入式系统开发者应该对Little-endian和Big-endian模式非常了解。采用Little-endian模式的CPU对操作数的存放方式是从低字节到高字节,而Big-endian模式对操作数的存放方式是从高字节到低字节。

例如,16bit宽的数0x1234在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

内存地址  存放内容
 0x4001    0x12
 0x4000    0x34

而在Big-endian模式CPU内存中的存放方式则为:

内存地址  存放内容
 0x4001    0x34
 0x4000    0x12
 
32bit宽的数0x12345678在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

内存地址  存放内容
 0x4003     0x12
 0x4002     0x34
 0x4001     0x56
 0x4000     0x78
 
而在Big-endian模式CPU内存中的存放方式则为:

内存地址  存放内容
 0x4003     0x78
 0x4002     0x56
 0x4001     0x34
 0x4000     0x12

相关定义如下:

i)
Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。(X86
CPU系列采用的位序)

ii)
Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

iii)
网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。

下面的这个程序是用来判断CPU采用的是哪种模式?

#include<stdio.h>
int main(){
union w 
{ 
int a; 
char b; 
} c; 
c.a = 1; 
if (c.b==1){
printf("The CPU is Litle-Endian\n");
}else{
printf("The CPU is Big-Endian\n");
}
return 0;
} /* end checkCPU*/
gcc -o checkCPU.o checkCPU.c
[root@node61 test]# ./checkCPU.o 
The CPU is Litle-Endian

本人本地虚拟机的是X86的小端模式的

至此上面使用hexdump为什么是顺序是倒着的原因了

有没有更加较便于方便的查看方式了?有,这也是较常用的方式,见下面的b)介绍;

b)以16进制和相应的ASCII字符显示文件里的字符

[root@node61 test]# hexdump -C test #常用
00000000 61 62 63 64 65 0a 41 42 43 44 45 0a |abcde.ABCDE.|
0000000c

这里既能显示16进制也能显示ascii码

c)以偏移量格式输出,参数 -s

[root@node61 test]# hexdump -C test 
00000000 61 62 63 64 65 0a 41 42 43 44 45 0a |abcde.ABCDE.|
0000000c
[root@node61 test]# hexdump -C -s 6 test 
00000006 41 42 43 44 45 0a |ABCDE.|
0000000c

第一行的abcde换行 的字符都没有了

其他hexdump还有很多的用法,具体可以参看man hexdump

以上就是本篇文章的全部内容,如果还有其他问题和不明白的地方可以给我们投稿或者在下方留言。