链接脚本使用一例2---将二进制文件 如图片、MP3音乐、词典一类的东西作为目标文件中的一个段
参考文章:
《程序员的自我修养——链接、转载与库》 P68
这里介绍两种方法,实现将将一张图片作为二进制可执行程序的一个段,其中第一种方法在我之前的博客中已经有所介绍,不过,那是采用的是交叉编译的方法,这次直接全部在PC机上完成;第二种方法是我在看上面的那本书的时候看到的,觉着也不错。
环境介绍: Win7 + VirtualBox + Debian6 + gcc version 4.4.5 (Debian 4.4.5-8)
第一种方法
- 目录结构
pengdl@debian:~/test/c/pic2$ tree -lh
.
|-- [ 135] data.S
|-- [ 811] main.c
|-- [ 91] Makefile
`-- [134K] peng.png
0 directories, 4 files
- data.S
这里需要注意:
这段代码是我直接从Linux内核中拷贝出来的,并做了修改,源文件如下(arch/arm/boot/compressed/piggy.S):
但是上面的代码除了需要修改.incbin之外,第一行的段属性部分也需要修改,将"#alloc"修改为"a",意思是:这个段可以重定位。如果不加段属性"a",运行时会发生段错误:
1: pengdl@debian:~/test/c/pic2$ ./main
2: input_data = (nil)
3: input_data_end = 0x2187e
4: size = 0x2187e
5:
6: Segmentation fault
使用objdump工具可以看看为什么?
先看看data.o:
1: pengdl@debian:~/test/c/pic2$ objdump -ht data.o
2:
3: data.o: file format elf32-i386
4:
5: Sections:
6: Idx Name Size VMA LMA File off Algn
7: 0 .text 00000000 00000000 00000000 00000034 2**2
8: CONTENTS, ALLOC, LOAD, READONLY, CODE
9: 1 .data 00000000 00000000 00000000 00000034 2**2
10: CONTENTS, ALLOC, LOAD, DATA
11: 2 .bss 00000000 00000000 00000000 00000034 2**2
12: ALLOC
13: 3 .piggydata 0002187e 00000000 00000000 00000034 2**0
14: CONTENTS, READONLY
15: SYMBOL TABLE:
16: 00000000 l d .text 00000000 .text
17: 00000000 l d .data 00000000 .data
18: 00000000 l d .bss 00000000 .bss
19: 00000000 l d .piggydata 00000000 .piggydata
20: 00000000 g .piggydata 00000000 input_data
21: 0002187e g .piggydata 00000000 input_data_end
再看看main:
1: pengdl@debian:~/test/c/pic2$ objdump -ht main | grep input_data
2: 0002187e g .piggydata 00000000 input_data_end
3: 00000000 g .piggydata 00000000 input_data
从data.o的objdump信息可以看到,它的.piggydata是不能重定位的,再看看main的信息,input_data的地址直接就是0,在main.c中会发生访问0地址的段错误!!从main的运行打印信息中也可以看到:input_data = (nil)
把.piggydata的段属性重新设置为"a",再看看objdump信息:
1: pengdl@debian:~/test/c/pic2$ objdump -ht data.o
2:
3: data.o: file format elf32-i386
4:
5: Sections:
6: Idx Name Size VMA LMA File off Algn
7: 0 .text 00000000 00000000 00000000 00000034 2**2
8: CONTENTS, ALLOC, LOAD, READONLY, CODE
9: 1 .data 00000000 00000000 00000000 00000034 2**2
10: CONTENTS, ALLOC, LOAD, DATA
11: 2 .bss 00000000 00000000 00000000 00000034 2**2
12: ALLOC
13: 3 .piggydata 0002187e 00000000 00000000 00000034 2**0
14:
CONTENTS, ALLOC, LOAD, READONLY, DATA
15: SYMBOL TABLE:
16: 00000000 l d .text 00000000 .text
17: 00000000 l d .data 00000000 .data
18: 00000000 l d .bss 00000000 .bss
19: 00000000 l d .piggydata 00000000 .piggydata
20: 00000000 g .piggydata 00000000 input_data
21: 0002187e g .piggydata 00000000 input_data_end
1: pengdl@debian:~/test/c/pic2$ objdump -ht main | grep input_data
2: 08069e63 g .piggydata 00000000 input_data_end
3: 080485e5 g .piggydata 00000000 input_data
可以看到,这下信息就正常了。
- main.c
1: #include <stdio.h>
2:
3: int main(int argc, const char *argv[])
4: {
5: int i;
6:
7: extern const unsigned long input_data;
8: extern const unsigned long input_data_end;
9:
10: const unsigned char *start = (const unsigned char *)&input_data;
11: const unsigned char *end = (const unsigned char *)&input_data_end;
12: unsigned long size = end - start;
13:
14: printf("input_data = %p\n", &input_data);
15: printf("input_data_end = %p\n", &input_data_end);
16: printf("size = %#0x\n", size);
17:
18:
19:
20: for(i=0; i<size; i++)
21: {
22: if(i % 16 == 0)
23: {
24: printf("\n%0#x\t\t",i);
25: }
26: printf("%3x ",start[i]);
27: }
28:
29: printf("\n");
30:
31:
32: return 0;
33: }
需要注意的是:如何使用data.S中的标号。
- Makefile
1: main:main.o data.o
2: $(CC) $^ -o $@
3:
4: data.o:data.S
5:
6: main.c:main.o
7:
8:
9: clean:
10: $(RM) *.o main
- peng.png 就是一张普通的文件,与图片的格式无关。
下面是运行结果:
pengdl@debian:~/test/c/pic2$ ./main
input_data = 0x80485e5 // 数值跟main的objdump信息是一致的
input_data_end = 0x8069e63
size = 0x2187e //注意指针相减的含义
00 89 50 4e 47 d a 1a a 0 0 0 d 49 48 44 52
0x10 0 0 1 28 0 0 1 89 8 2 0 0 0 b6 25 39
0x20 5 0 0 0 9 70 48 59 73 0 0 e c4 0 0 e
0x30 c4 1 95 2b e 1b 0 0 20 0 49 44 41 54 78 da
0x40 ec bd 67 5f 23 59 b2 af db 1f eb ee b3 a7 bb c
0x50 de a 79 21 bc 24 bc 40 de 23 ef bd f0 de 43 51
0x60 a6 ed 9c fb 1 ef 3f 56 64 2e a5 4 d5 33 67 df
0x70 17 73 5e 54 fe 9e d1 24 22 11 a2 2b 1f 45 c4 b2
0x80 3f 7d fe eb 4f f0 ed af bf 7a f8 e3 cf af bf ff
0x90 c1 e0 9c f9 f2 db ef 2f df 7e 7d 7c f9 fc f0 e9
0xa0 5 dc 3e 3e 5d dd dd 9f 5f df 9c 5e 5e 9d 5c 5c
0xb0 82 e3 cb cb a3 f3 ab c3 b3 cb 83 b3 b3 fd d3 53
0xc0 a6 7d 7c dc 3e 3c 68 1d ec b7 3a 6d d0 de ef b4
下面是用winhex看到的:

第二种方法
使用objcopy工具
目录结构:
pengdl@debian:~/test/c/pic$ tree -lh
.
|-- [ 999] main.c
|-- [ 77] Makefile
|-- [135K] peng.o
`-- [134K] peng.png
0 directories, 4 files
- peng.o
使用如下命令生成peng.o:
objdcopy –I binary –O elf32-i386 –B i386 peng.png peng.o
objdump –ht peng.o
参数解释:
-I --input-target <bfdname> Assume input file is in format <bfdname>
-O --output-target <bfdname> Create an output file in format <bfdname>
-B --binary-architecture <arch> Set arch of output file, when input is binary
-h, --[section-]headers Display the contents of the section headers
-t, --syms Display the contents of the symbol table(s)
1: pengdl@debian:~/test/c/pic$ objdump -ht peng.o
2:
3: peng.o: file format elf32-i386
4:
5: Sections:
6: Idx Name Size VMA LMA File off Algn
7: 0 .data 0002187e 00000000 00000000 00000034 2**0
8:
CONTENTS, ALLOC, LOAD, DATA
9: SYMBOL TABLE:
10: 00000000 l d .data 00000000 .data
11: 00000000 g .data 00000000 _binary_peng_png_start
12: 0002187e g .data 00000000 _binary_peng_png_end
13: 0002187e g *ABS* 00000000 _binary_peng_png_size
符号“_binary_peng_png_start”、“_binary_peng_png_end”和“_binary_peng_png_size”分别表示该图片文件在内存中的起始地址、结束地址和大小。
可以看到,图片数据被放到了.data段。
- main.c
1: #include <stdio.h>
2:
3: int main(int argc, const char *argv[])
4: {
5: int i;
6:
7: extern const unsigned long _binary_peng_png_start;
8: extern const unsigned long _binary_peng_png_size;
9: extern const unsigned long _binary_peng_png_end;
10:
11: const unsigned char *start = (const unsigned char *)&_binary_peng_png_start;
12: const unsigned long size = (const unsigned long)&_binary_peng_png_size;
13: const unsigned char *end = (const unsigned char *)&_binary_peng_png_end;
14:
15: printf("_binary_peng_png_start = %p\n", &_binary_peng_png_start);
16: printf("_binary_peng_png_size = %p\n", &_binary_peng_png_size);
17: printf("_binary_peng_png_end = %p\n", &_binary_peng_png_end);
18:
19:
20:
21: for(i=0; i<size; i++)
22: {
23: if(i % 16 == 0)
24: {
25: printf("\n%0#x\t\t",i);
26: }
27: printf("%3x ",start[i]);
28: }
29:
30: printf("\n");
31:
32:
33: return 0;
34: }
- Makefile
1: main:main.o peng.o
2: $(CC) $^ -o $@
3:
4: main.c:main.o
5:
6:
7: clean:
8: $(RM) *.o main
下面是运行结果:
pengdl@debian:~/test/c/pic$ ./main
_binary_peng_png_start = 0x80496f4
_binary_peng_png_size = 0x2187e
_binary_peng_png_end = 0x806af72
0 89 50 4e 47 d a 1a a 0 0 0 d 49 48 44 52
0x10 0 0 1 28 0 0 1 89 8 2 0 0 0 b6 25 39
0x20 5 0 0 0 9 70 48 59 73 0 0 e c4 0 0 e
0x30 c4 1 95 2b e 1b 0 0 20 0 49 44 41 54 78 da
0x40 ec bd 67 5f 23 59 b2 af db 1f eb ee b3 a7 bb c
0x50 de a 79 21 bc 24 bc 40 de 23 ef bd f0 de 43 51
0x60 a6 ed 9c fb 1 ef 3f 56 64 2e a5 4 d5 33 67 df
0x70 17 73 5e 54 fe 9e d1 24 22 11 a2 2b 1f 45 c4 b2
0x80 3f 7d fe eb 4f f0 ed af bf 7a f8 e3 cf af bf ff
0x90 c1 e0 9c f9 f2 db ef 2f df 7e 7d 7c f9 fc f0 e9
0xa0 5 dc 3e 3e 5d dd dd 9f 5f df 9c 5e 5e 9d 5c 5c
。。。。。。
完!!!
链接脚本使用一例2---将二进制文件 如图片、MP3音乐、词典一类的东西作为目标文件中的一个段的更多相关文章
- 链接脚本(Linker Script)应用实例(一)使用copy table将函数载入到RAM中运行
将函数载入到RAM中运行需要以下三个步骤: (1)用编译器命令#pragma section "<section name>" <user functions&g ...
- 四、u-boot 链接脚本
4.1 C语言中的段 编译器在编译程序的时候,将程序中的所有的元素分成了一些组成部分,各部分构成一个段,所以说段是可执行程序的组成部分. 代码段:代码段就是程序中的可执行部分,直观理解代码段就是函数堆 ...
- GNU linker script,ld script,GNU链接脚本
https://blog.csdn.net/itxiebo/article/details/50937412 https://blog.csdn.net/itxiebo/article/details ...
- [转]Linux下的lds链接脚本详解
转载自:http://linux.chinaunix.net/techdoc/beginner/2009/08/12/1129972.shtml 一. 概论 每一个链接过程都由链接脚本(lin ...
- Linux下的lds链接脚本简介
转载:http://hubingforever.blog.163.com/blog/static/171040579201192472552886/ 一. 概论 每一个链接过程都由链接脚本(lin ...
- makefile使用.lds链接脚本以及 $@ ,$^, $,< 解析
先来分析一个简单的.lds链接脚本 例1,假如现在有head.c init.c nand.c main.c这4个文件: 1.1 首先创建链接脚本nand.lds: SECTIONS { firtst ...
- [转]Linux下的链接脚本基础
[转]http://linux.chinaunix.net/techdoc/beginner/2009/08/12/1129972.shtml 1. 前言 (1)每一个链接过程都由链接脚本(linke ...
- Linux下的lds链接脚本详解【转】
转自:http://www.cnblogs.com/li-hao/p/4107964.html 转载自:http://linux.chinaunix.net/techdoc/beginner/2009 ...
- makefile使用.lds链接脚本以及 $@ ,$^, $,< 解析【转】
转自:http://www.cnblogs.com/lifexy/p/7089873.html 先来分析一个简单的.lds链接脚本 例1,假如现在有head.c init.c nand.c main. ...
随机推荐
- BootLoader的一些知识
在嵌入式操作系统中,BootLoader是在操作系统内核运行之前运行.可以初始化硬件设备.建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境.在嵌入 ...
- duilib入门简明教程 -- 界面布局(9) (转)
原文转自:http://www.cnblogs.com/Alberl/p/3343806.html 上一个教程实现的标题栏代码中,并没有看到处理自适应窗口大小的代码,但是窗口大小变化后,按钮的 ...
- 《Linux命令行与shell脚本编程大全 第3版》Linux命令行---46
以下为阅读<Linux命令行与shell脚本编程大全 第3版>的读书笔记,为了方便记录,特地与书的内容保持同步,特意做成一节一次随笔,特记录如下:
- 例说linux内核与应用数据通信系列【转】
转自:http://blog.csdn.net/shallnet/article/details/47865169 版权声明:本文为博主原创文章,未经博主允许不得转载.如果您觉得文章对您有用,请点击文 ...
- Hrbust 2320 OX (博弈)
题目链接 Hrbust 2320 用三进制来存储整个棋盘的状态. 设$dp[status][now]$为轮到$now$下棋的时候是必胜必败还是平局. 那么若当前能延伸出的所有状态中存在必败态的,则当 ...
- TopCoder SRM 722 Div1 Problem 600 DominoTiling(简单插头DP)
题意 给定一个$12*12$的矩阵,每个元素是'.'或'X'.现在要求$1*2$的骨牌铺满整个矩阵, 'X'处不能放置骨牌.求方案数. 这道题其实和 Uva11270 是差不多的,就是加了一些条件. ...
- Codeforces 777C Alyona and Spreadsheet(思维)
题目链接 Alyona and Spreadsheet 记a[i][j]为读入的矩阵,c[i][j]为满足a[i][j],a[i - 1][j], a[i - 2][j],......,a[k][j] ...
- luogu P1941 飞扬的小鸟
题目描述 Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙.如果小鸟一不小心撞到了水管或者掉在地上的话,便 ...
- Maven项目管理工具初体验
在最前面声明,本文不涉及任何原理,只是对使用方法和期间遇到的问题如何解决.主要是随着年纪原来越大,越觉得好记星不如烂笔头的深意,同时如果能够帮助谁,那就最好不过了. 前两天自己做一个项目,然后好心朋友 ...
- JavaScript 深克隆
深克隆 function judgeType(arg){//判断js数据类型 return Object.prototype.toString.call(arg).slice(8,-1); } fun ...