基础类型
子曾经曰过:程序员要对自己所写程序的每个字节都了如指掌。
Talk is cheap,show me the binary code.
by 高尔基
对于数据类型的分析,采用二进制文件和运行时的内存2个方面着手。
int / unsigned int
int
int n = 10; // 全局整型变量n,编译链接后将放到.data段,
// 而且只有这一个变量,那它就是放到.data的起始位置
int main() // C语言的入口函数
{
int n1 = n;
}
二进制文件
执行命令:
arm-none-eabi-objdump -h main.elf
得到elf文件各段的信息, 重点看.data段
main.elf: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 000000bc 00000000 00000000 00010000 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000004 a0000000 000000bc 00020000 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .comment 00000031 00000000 00000000 00020004 2**0
CONTENTS, READONLY
3 .ARM.attributes 0000002e 00000000 00000000 00020035 2**0
CONTENTS, READONLY
- 其中Size是段的大小,.data就是4,因为int型变量n就是4个字节大小。
- VMA是运行地址0xa0000000。
- LMA是load memory address及加载地址,为0xbc。
- File off为文件中的偏移,为0x20000。
- Algn对为对齐边界位置2**2即2的2次方=4,即4字节对齐。
- 下面的是段的相关属性,暂不表。
注意.data的地方:File off为0x00020000,表示.data段的内容放在main.elf文件的0x00020000开始的位置。
所以我们执行命令:
hexdump -C -s 0x20000 main.elf
得到如图高亮的位置 0a,就是10进制的10。
内存
需要用到qemu命令x和xp命令
x /
fmt addr
Virtual memory dump starting at addr.
xp /
fmt addr
Physical memory dump starting at addr.
fmt is a format which tells the command how to format the data. Its syntax is: /{count}{format}{size}
count
is the number of items to be dumped.
format
can be x (hex), d (signed decimal), u (unsigned decimal), o (octal), c (char) or i (asm instruction).
size
can be b (8 bits), h (16 bits), w (32 bits) or g (64 bits). On x86, h
or w
can be specified with the i format to respectively select 16 or 32 bit code instruction size.
因我们还没有启用MMU,物理地址和虚拟地址相同,我们用x或xp均可。
查看代码段的加载地址 0xbc 处的一个4字节的数据,用10进制的格式显示。执行:
x /1dw 0xbc
得到结果:10,如图:
查看代码段的运行时地址 0xa0000000 处的一个4字节的数据,用10进制的格式显示。执行:
x /1dw 0xa0000000
得到结果:10,如图:
再试一个负数-2:
int n = -2; // 全局整型变量n,编译链接后将放到.data段,
// 而且只有这一个变量,那它就是放到.data的起始位置
int main() // C语言的入口函数
{
int n1 = n;
}
我们看到在内存中的16进制表示,这个是-2的补码表示。
综上:将int型变量在的分析完成。
unsigned int
对于正整数赋值给unsigned int,和int类似。重点研究一下将负整数赋值给unsigned int有什么特别的。
- 对于无符号整形-2
unsigned int n = -2; // 全局无符号整型变量n
int main() // C语言的入口函数
{
int n1 = n;
}
查看代码段的运行时地址 0xa0000000 处的一个4字节的数据,用16进制的格式显示。执行:
x /1dw 0xa0000000
如图:
说明:将整形的负数赋值给无符号整形变量,是将负数的补码赋给变量。
下面类型的分析就只dump内存的内容来分析,因为内存中的数据就是从二进制文件加载来的。有兴趣的读者可自行验证,方法与int型类似。
(unsigned )long、short、char
与int、unsigned int类似,读者可自行实验。
float
上代码:
float f = -2.5f;
int main() // C语言的入口函数
{
}
得到:
如图这个0xc0200000怎么来的呢?
这要从float的IEEE754标准来分析。参考:IEEE754 浮点数的表示方法_Dablelv的博客专栏-CSDN博客_浮点数表示方法
配合IEEE754标准,在网址:https://float.exposed/ 上可以直接查看输入的float数值的各种表示方式,比如本例中的-2.5,高亮的地方就是16进制的表示法:
float收工。
double
double d = -2.5;
int main() // C语言的入口函数
{
}
因为double占8个字节,我们要1个16进制的g,得到:
同float,在网址:https://float.exposed/ 输入double型的-2.5。得到:
复合类型
指针
上代码:
int n = 0xbabebabe;
int * p ;
int main() // C语言的入口函数
{
p =