Chinaunix首页 | 论坛 | 博客
  • 博客访问: 250046
  • 博文数量: 88
  • 博客积分: 1429
  • 博客等级:
  • 技术积分: 523
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-18 15:31
文章分类

全部博文(88)

文章存档

2017年(2)

2016年(24)

2013年(1)

2012年(24)

2011年(15)

2010年(22)

我的朋友

分类: LINUX

2010-04-06 18:00:44

 
FROM:http://blog.chinaunix.net/u/17660/showart_257195.html
word expression就是在当前位置放一个word型的值,这个值就是expression
举例来说,
_rWTCON:
.word 0x15300000
就是在当前地址,即_rWTCON处放一个值0x15300000

翻译成intel的汇编语句就是:
_rWTCON dw 0x15300000

就是在当前位置放个expression的值。
 
FROM:http://blog.chinaunix.net/u2/68846/showart_694880.html
PS:在u-boot源码时遇到_armboot_start、_bss_start等这些变量,不知道指向什么地址,于是查了一下,弄清了ARM汇编中“.word”这个伪指令是什么意思了,感觉自己很菜。借鉴一下网友帖子的内容,关键在帖子最后的总结:

        汇编和C引用变量的不同:汇编是“绝对”引用,即没有指针的概念,引用得到的就是值;c语言是“间接”引用,相当于指针的概念,引用地址变量,得到的就是该变量所指的内容值。

感谢原作者,以下为原帖:

aaronwong: u-boot中代码的疑问(_armboot_start与_start)?
---------------------------
我使用的是u-boot-1.3.0-rc2。在cpu/pxa/start.S中,有如下的标号定义:
_TEXT_BASE:
.word TEXT_BASE /*uboot映像在SDRAM中的重定位地址,我设置为0xa170 0000 */

.globl _armboot_start
_armboot_start:
.word _start /*_start是程序入口,链接完毕它的值应该是0xa170 0000=TEXT_BASE*/
/* 这句话的意思应该是在_armboot_start标号处,保存了_start的值,也就是说,_armboot_start是存放_start的地址,该地址对应的存储单元内容是0xa170 0000*/
/*
* These are defined in the board-specific linker script. 下面的定义与上面应该是一个意思。
*/
.globl _bss_start
_bss_start:
.word __bss_start
======================
按照上面的理解,__bss_start是uboot 的bss段起始地址,那么uboot映像的大小就是__bss_start - _start;在relocate代码段中计算uboot的大小时,也体现了这一点。
实际上,_armboot_start并没有实际意义,它只是在"ldr r2, _armboot_start"中用來寻址_start的值而已,_bss_start也是一样的道理,真正有意义的应该是_start和 __bss_start本身。
但是,令我不解的是,在C入口函数start_armboot()中(对应文件为lib_arm/board.c),有如下代码:
void start_armboot (void)
{
.........
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t)); //第一句话
..........
monitor_flash_len = _bss_start - _armboot_start; //第二句话
...............
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN); //第三句话
..........
}
==============================================
按照上面的理解,_armboot_start与_bss_start都是没有实际意义的,它们只是一个地址,有实际意义的是地址中的内容_start和 __bss_start(虽然也还是地址)。象第一句话,其“意图”很明显,是把gd作为全局数据结构体的指针,并初始化为“SDRAM中的uboot起始地址(即TEXT_BASE)-CFG_MALLOC_LEN-全局数据结构体大小”。
要实现这个“意图”,应该是写成:gd = (gd_t*)(_start - CFG_MALLOC_LEN - sizeof(gd_t));或者gd = (gd_t*)(TEXT_BASE- CFG_MALLOC_LEN - sizeof(gd_t));才对阿?用_armboot_start来作运算应该是没有任何意义才对!?
第二句话也是一样的道理,它的意图是要计算u-boot映像的大小,应该写成__bss_start - _start才对阿?
我使用readelf工具查看编译所得到的uboot映像文件得到信息如下:
[aaronwong@localhost build]$ readelf -s u-boot|grep _start
1018: a1700048 0 NOTYPE GLOBAL DEFAULT 1 _bss_start
1083: a1700044 0 NOTYPE GLOBAL DEFAULT 1 _armboot_start
1142: a1700000 0 NOTYPE GLOBAL DEFAULT 1 _start
1197: a171b070 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
上面我删除了与该讨论无关的包含“_start""t的标号信息。
显然,我前面的理解应该是正确的(_start=TEXT_BASE=0xa170 0000)。那么u-boot源代码中的monitor_flash_len=_bss_start - _armboot_start=0xa1700048 - 0xa1700044 = 4,有什么意义??
迷茫中,期盼大虾指点迷津,谢谢~!!!


eltshan: [Re: aaronwong]
-----------------
1018: a1700048 0 NOTYPE GLOBAL DEFAULT 1 _bss_start
1083: a1700044 0 NOTYPE GLOBAL DEFAULT 1 _armboot_start
1142: a1700000 0 NOTYPE GLOBAL DEFAULT 1 _start
1197: a171b070 0 NOTYPE GLOBAL DEFAULT ABS __bss_start

我想:
_start所在的地址是a1700000,
_armboot_start 所在的地址是a1700044,
那么 根据这句:
_armboot_start: .word _start
所以_armboot_start的值应该是a1700000

所以
monitor_flash_len = _bss_start - _armboot_start = a171b070 - a1700000 = 1b070
而不是你说的 = 4

以上个人意见.


aaronwong: [Re: eltshan]
-------------------
谢谢,eltshan!你的理解是正确的,不过我看了之后还是没能想得很明白,因为我在想,按你所说,那么_start的值应该是多少呢?难道是“b reset”这条指令的机器码?所以我对ELF格式的u-boot映像文件作了反汇编,分析之后终于找到了症结所在。以下是部分分析过程,首先是反汇编:
arm-iwmmxt-linux-gnueabi-objectdump -D u-boot > u-boot.s
并提取了monitor_flash_len = _bss_start - _armboot_start;这条语句相关的反汇编代码如下:
==============================
a1700044 <_armboot_start>:
a1700044: a1700000 .word 0xa1700000

a1700048 <_bss_start>:
a1700048: a171b070 .word 0xa171b070

a171b070 :
a171b070: 00000000 .word 0x00000000

.....
a1700f40: e59f41d0 ldr r4, [pc, #464] ; a1701118
//r4=[a1701118]=a1700044
.....
a1700f7c: e59f3198 ldr r3, [pc, #408] ; a170111c
//r3=[a1700044]=a1700048
a1700f80: e5942000 ldr r2, [r4]
//r2=[a1700044]=a1700000
a1700f84: e59f4194 ldr r4, [pc, #404] ; a1701120
//r4=[a1701120]=a1719d24
a1700f88: e5933000 ldr r3, [r3]
//r3=[a1700048]=a171b070
a1700f8c: e0623003 rsb r3, r2, r3
//r3= r3-r2 = a171b070-a1700000 = 1b070;
a1700f90: e59f218c ldr r2, [pc, #396] ; a1701124
//r2=[a1701124]=a171b070
a1700f94: e5823000 str r3, [r2]
//monitor_flash_len=[r2]=r3=1b070
......

a1701118: a1700044 .word 0xa1700044
a170111c: a1700048 .word 0xa1700048
a1701120: a1719d24 .word 0xa1719d24
a1701124: a171b070 .word 0xa171b070
========================================
上面//是我自己的注释。这表明,你的理解的确是正确的。
经过这个过程之后,我终于认识到自己的误解在哪里了。原来,我是把"汇编语言中LDR伪指令对符号的引用"与"C语言中对汇编程序中符号/常量/变量的引用"搞混淆了。我想说明以下几点:

(1) readelf以及u-boot.map和System.map所给出的符号表中符号的值,实际上是表示符号所在的地址,而不是指符号本身的值。

(2) 汇编语言中没有指针的概念,因此对符号的引用是"赤裸裸"的。例如:
==========
.globl _armboot_start
_armboot_start: .word _start
ldr r2, _armboot_start
==========
实际上反汇编以后是:
============
a1700044 <_armboot_start>:
a1700044: a1700000 .word 0xa1700000
a1700074: e51f2038 ldr r2, [pc, #-56] ; a1700044 <_armboot_start>
============
也就是说,_armboot_start是一个地址0xa1700044,其中的内容是0xa1700000,上面对_armboot_start的引用是直接将其替换为其表示的地址0xa1700044,而非其中的内容0xa1700000。这就是"赤裸裸"的引用。

(3) C语言则不同,对变量/符号/常量的引用必须要通过地址来寻址,不管是全局变量还是局部变量,不同的是局部变量在生命期结束后,所占的地址空间会被释放而已。即使是函数调用时的参数传递,虽然是将实参的值"拷贝"给形参,但"拷贝"的过程也是通过实参和形参的地址来对两者进行访问的。
所以,在C语言中的 "monitor_flash_len = _bss_start - _armboot_start" 这句话中对_armboot_star的引用,实际上是把它用作了指针,把它作为访问对象的地址来使用,通过这个地址即a1700044 来访问对应存储空间所存放的内容亦即0xa1700000,_bss_start也是同样的道理。所以这句话实际上是monitor_flash_len =[a1700048]-[0xa1700044]=a171b070-a1700000 = 1b070,这样就得到了正确的结果。

现在,我们再回答最前面的问题:_start的值是什么?_start表示地址0xa1700000 ,在汇编语言中,对_start的"绝对引用"(这里是与用相对寻址进行跳转进行区别)就是将其替换为0xa1700000,但其中存放的内容的的确确就是"b reset"这条指令的机器码,所以如果在C语言中引用_start,得到的结果反而就是这个指令的机器码了。其实这个问题很简单,只是和C语言的引用搅在一起,一些概念被偷换了而已。

FROM:http://blog.chinaunix.net/u/17660/showart_257195.html
我把bin文件反汇编,想通过这种方法来找找这个.word究竟干什么。
原汇编程序:(start.S)
.globl _start
_start: b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq

_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq

.balignl 16,0xdeadbeef

_TEXT_BASE:
.word TEXT_BASE

.globl _armboot_start
_armboot_start:
.word _start

.globl _bss_start
_bss_start:
.word __bss_start

.globl _bss_end
_bss_end:
.word _end

reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0

对应的反汇编:
00000000 [0xea000012] b 0x50
00000004 [0xe59ff014] ldr pc,0x00000020 ; = #0x33f80140
00000008 [0xe59ff014] ldr pc,0x00000024 ; = #0x33f801a0
0000000c [0xe59ff014] ldr pc,0x00000028 ; = #0x33f80200
00000010 [0xe59ff014] ldr pc,0x0000002c ; = #0x33f80260
00000014 [0xe59ff014] ldr pc,0x00000030 ; = #0x33f802c0
00000018 [0xe59ff014] ldr pc,0x00000034 ; = #0x33f80320
0000001c [0xe59ff014] ldr pc,0x00000038 ; = #0x33f80380
00000020 [0x33f80140] mvnccs r0,#0x10 ; ? rn = 0x8
00000024 [0x33f801a0] mvnccs r0,#0x28 ; ? rn = 0x8
00000028 [0x33f80200] mvnccs r0,#0, 4 ; ? rn = 0x8
0000002c [0x33f80260] mvnccs r0,#6 ; ? rn = 0x8
00000030 [0x33f802c0] mvnccs r0,#0xc ; ? rn = 0x8
00000034 [0x33f80320] mvnccs r0,#0x80000000 ; ? rn = 0x8
00000038 [0x33f80380] mvnccs r0,#2 ; ? rn = 0x8
0000003c [0xdeadbeef] cdple p14,0xa,c11,c13,c15,7
00000040 [0x33f80000] mvnccs r0,#0 ; ? rn = 0x8
00000044 [0x33f80000] mvnccs r0,#0 ; ? rn = 0x8
00000048 [0x33f96650] mvnccs r6,#0x5000000 ; ? rn = 0x9
0000004c [0x33f9ab80] mvnccs r10,#0x20000 ; ? rn = 0x9
00000050 [0xe10f0000] mrs r0,cpsr
00000054 [0xe3c0001f] bic r0,r0,#0x1f
00000058 [0xe38000d3] orr r0,r0,#0xd3
0000005c [0xe129f000] msr cpsr_cf,r0


这么看来,
_undefined_instruction: .word undefined_instruction
这句对应的反汇编是:
mvnccs r0,#0x10 ;

这么一来我又更糊涂了。

到ChinaUnix求助。幸好碰到一位热心的网友wheelz,详细地给我解答了。
帖子链接如下:


现在总结wheelz的回答,说说这个.word的作用。

word expression就是在当前位置放一个word型的值,这个值就是expression
举例来说,
_rWTCON:
.word 0x15300000
就是在当前地址,即_rWTCON处放一个值0x15300000

翻译成intel的汇编语句就是:
_rWTCON dw 0x15300000

就是在当前位置放个expression的值。 原来如此啊。

PS:
贴一个##的作用。
#define _syscall0(type,name) \
type name(void) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name)); \
if (__res >= 0) \
return (type) __res; \
errno = -__res; \
return -1; \
}
__NR_##name是系统调用号,##指的是两次宏展开.即用实际的系统调用名字代替"name",然后再把__NR_...展开.如name == ioctl,则为__NR_ioctl。
阅读(944) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

enjoy-linux2012-10-25 00:13:23

think you !我找到答案了