彻底倒塌了~~~keil的CARM编译器好象不能设置生成相对跳转代码

[复制链接]
14616|58
mybao 发表于 2007-4-12 13:33 | 显示全部楼层

圈圈这个问题想复杂了

  
 楼主| computer00 发表于 2007-4-12 14:02 | 显示全部楼层

不是我把问题想复杂了,而是事实上它就如此,我也没办法

如果将代码指定在ROM区,那么它就有可能产生绝对跳转到ROM区的指令,如果我把代码区指定在RAM区,<br />那么我将没办法把代码烧录到FLASH中去,因为地址不对.<br /><br />事实上,我现在的代码就是即在FLASH中运行,又要在RAM中运行.复位后在FLASH中运行,<br />然后有必要时,我在主函数中将代码复制到RAM中,再跳转到那里去执行。<br /><br />当然,也可以如你所说,在FLASH中只保留复制代码的部分程序,然后平时都在RAM中运行.<br />但是,我没办法指定产生的函数地址是在RAM区间,而又把这个函数代码烧录到FLASH中去,因为<br />这个开发环境就这样,函数地址是多少,它就要烧录到哪里去.&nbsp;如果你指定某个函数的<br />入口地址是在RAM区间的,那么在下载程序的时候,就出错了.所以我必须先让它产生<br />在FLASH里面运行的代码,再复制到RAM中,还能继续运行。<br />
农民讲习所 发表于 2007-4-12 14:42 | 显示全部楼层

是否和优化有关?

一般是生成相对跳转,优化过分可能成为绝对跳转.
djyos 发表于 2007-4-12 15:01 | 显示全部楼层

这好像不是相对跳转和绝对跳转的问题

&nbsp;&nbsp;&nbsp;&nbsp;我们知道,C语言中函数名是可以作为符号常量使用的,如果函数的地址不是绝对地址的话,那才真的倒塌了呢。<br />&nbsp;&nbsp;&nbsp;&nbsp;因为这个,我一直不明白ads的位置无关是怎么实现的,也许我对“位置无关”理解错了吧,没仔细研究过,有空的时候好好看看。
 楼主| computer00 发表于 2007-4-12 15:37 | 显示全部楼层

因为有相对跳转的指令,还有PC也可以用

例如B指令,第一个字节是0xEA,后面的3个字节是相对地址.<br />例如下面这条指令:&nbsp;EA00000E,相对地址是0x0E,即14,由于ARM指令是<br />4字节宽度,因此地址可以以4字节为单位,这样可以节省2个没用的bit出来,<br />所以这个指令中的14实际上是除了4的结果,因此在计算实际地址时需要乘以4,即14*4=56.<br />再由于ARM7的三级流水线,执行这条指令时,PC值为当前地址+8,所以<br />这个指令实际上是跳转<br />到这条地址后面的第64(0x40)字节处执行,如果当前PC为0,即复位地址,那么就相当于一<br />条Jump&nbsp;0x00000040的指令。如果我这时已经把这个指令复制到地址0x0C000000处去了,<br />那么这个地址偏移0x40,就是0x0C000040,这就相当于一条Jump&nbsp;0x0C000040的指令了.&nbsp;<br />这样就可以实现代码与地址无关了,放在哪里都可以正常运行.<br /><br /><br />但是看看下面这个生成的代码就不一样了,这个是一个函数调用,CARM编译器使用了BX指令<br />来跳转,是考虑到被调用的函数可能处于不同的模式(由R0的最低位来决定ARM和THUMB模式),<br />但是它在加载R0时,没有根据当前PC值来加载要跳转到的地址,而是直接加载了要跳转<br />到的函数的绝对地址.如果我这时运行在RAM里,那么一调用这个函数,程序就跑到<br />FLASH里面去了。<br /><br /><br />&nbsp;&nbsp;&nbsp;155:&nbsp;&nbsp;SysClkInit();&nbsp;<br />0x00080478&nbsp;&nbsp;E59F00FC&nbsp;&nbsp;LDR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R0,[PC,#0x00FC]&nbsp;&nbsp;<font color=#0000FF>//SysClkInit这个函数的地址保存在PC+0x00FC这个单元中(注意PC是当前地址+8)</font><br />0x0008047C&nbsp;&nbsp;E1A0E00F&nbsp;&nbsp;MOV&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R14,PC&nbsp;&nbsp;<font color=#0000FF>//保存返回地址到R14中,等下好返回</font><br />0x00080480&nbsp;&nbsp;E12FFF10&nbsp;&nbsp;BX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R0&nbsp;<font color=#0000FF>//根据R0中的值跳转到函数中</font><br />............................................<br /><font color=#0000FF>//省略中间的了</font><br />...........................................<br />0x0008057C&nbsp;&nbsp;00011000&nbsp;&nbsp;DD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0x00011000&nbsp;&nbsp;<font color=#0000FF>//这个地址就是前面计算出来的(8057C=80478+8+FC)</font><br /><br /><br />结果,R0的值就是0x11000了,SysClkInit这个函数的地址刚好就是0x11000,那么在FLASH中跳转过去是没问题的。<br />但是如果这时代码在RAM中运行,也跳到这个地址去,当然就不行了。<br /><br />它应该保存这个这个函数与当前PC之间的差值.&nbsp;运行时,取出相对地址,加上PC后再<br />放到R0中,然后再用BX&nbsp;R0跳转到指定的函数入口地址.<br /><br /><br />所长所说的优化问题,我也试过了,不管改成什么样的级别,这里的代码都是一样的,不变.<br /><br /><br /><br /><br />
minmindede 发表于 2007-4-12 16:42 | 显示全部楼层

圈圈的问题,我是

通过scatter来解决的,你不能用,不知道怎么帮你。&nbsp;如果有mem&nbsp;remap就不存在这个问题
 楼主| computer00 发表于 2007-4-12 17:23 | 显示全部楼层

恩,我现在已经把程序弄到RealView上来了,

修改了一些地方,编译通过,并且可以运行了。还没测试它是否会跳回到FLASH中......<br /><br />在RealView中可以将Read-Only&nbsp;Position&nbsp;Independent勾上,不知道是否奏效了~~~~~来不及测试了,<br />先去吃饭~~~~还要自己修改一下keil的启动文件才行的~~~~~希望这次别再让我倒塌了.....
high 发表于 2007-4-12 17:43 | 显示全部楼层

估计有些人没有明白

对蛋蛋的应用,我提供2个办法参考:<br /><br />1.继续死磕position&nbsp;imdependence.搞定後把结果通报一下。<br /><br />2.简单办法:固定地址运行。<br /><br />&nbsp;&nbsp;串口接收的程序使用固定地址编译。恰好也放到对应地址运行。<br /><br />&nbsp;&nbsp;内存地址是&nbsp;0x40004000&nbsp;ro_base&nbsp;=&nbsp;0x40004000生产一个bin<br />&nbsp;&nbsp;串口接收并copy到0x40004000.<br />&nbsp;&nbsp;run().肯定不会回去了。当然还要小心中断引起的跳转。
mybao 发表于 2007-4-12 17:51 | 显示全部楼层

建议圈圈研究一下偶贴的那段启动代码

<font color=#040BF2>当然,也可以如你所说,在FLASH中只保留复制代码的部分程序,然后平时都在RAM中运行.</font><br /><br />不是这样的,启动代码和主程序是一个整体,一起烧到FLASH,启动代码部分的执行和地址无关,比如你设置存储器start&nbsp;address&nbsp;是0XC000000(其实别的&nbsp;地址也不用加了),生成的bin文件按理说要从0XC000000开始执行,但是把bin文件直接烧到起始地址为0x00的FLASH,启动代码首先上电执行,会把所有代码复制到0XC000000开始的SDRAM,然后在跳转到SDRAM执行,<font color=#F20003>启动代码与地址无关</font><br /><br /><br /><font color=#00FF00>但是,我没办法指定产生的函数地址是在RAM区间,而又把这个函数代码烧录到FLASH中去</font><br /><br /><br />实际上确实就是这样做的,倒塌吧。<br />
 楼主| computer00 发表于 2007-4-12 20:31 | 显示全部楼层

我用的是Ulink,Ulink负责把对应的地址的值烧到FLASH中

因此如果我在编程的时候告诉编译器,“生成的bin文件要从0XC000000开始执行”,那么,Ulink就会傻傻的把代码<br />下载到从0xC000000的地方去,而这个地址不是FLASH,是RAM,所以下载就会不成功。<br /><br /><br />至于high所说,第一点我是找了很久都没结果,要不就给Keil的技术支持发邮件了,问问他们应该怎么在CARM里面设置。<br />第二点,倒是可行,但是太麻烦了,而且将来也不大好用,我喜欢生成相对跳转的指令,<br />这样放哪都可以运行,不是很好么?并且如果把RO地址设置在0x0C000000处,那么产生<br />的*.bin文件会不会有200多M那么大?因为前面要填充很多很多0...虽然我可以写个<br />程序,在下载时省略掉前面的0,但是每次弄这么大的程序,还是蛮晕的...<br /><br />按照high所说的方法二,我现在做的是一个boot程序,所以第一步就需要用ulink下载,<br />然后再把这个boot程序的RO地址改到RAM里,然后通过串口把新生成的boot代码加载到RAM中,<br />再来运行新的boot程序,那么这时的boot程序就是会在RAM里面跳转了,然后我再把这个<br />程序自己固化到FLASH中,然后下次启动时,就先复制代码到RAM,然后跳转到RAM,<br />这样就会在RAM中执行了。这么多步骤,蛮罗嗦的.........<br /><br />还是先玩玩RealView吧,晚上回去测试一下,看是不是OK了,如果OK了,那么我就决定<br />以后用RealView来编译了~~~~~~~~
djyos 发表于 2007-4-12 21:06 | 显示全部楼层

好好研究

在C语言里,下列语句是合法的:<br />void&nbsp;func(void);<br />void&nbsp;(*&nbsp;const&nbsp;faddr)(void)&nbsp;=&nbsp;func;<br />void&nbsp;func(void)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;…………<br />}<br /><br />如果可以实现运行时func地址的动态性,那faddr变量的const属性怎么办?圈圈要是研究明白了,别忘了把结果贴上来,翘首等待中.
mybao 发表于 2007-4-12 21:48 | 显示全部楼层

不能Ulink直接下载

Ulink就会傻傻的把代码下载到从0xC000000的地方<br /><br />你说的下载什么意思,你也知道FLASH不能直接下载,bin文件用一个小程序烧写到FLASH不就行了吗,只不过这个小程序要下载到SDRAM运行。<br /><br />把RO地址设置在0x0C000000,先放代码,再放常数,bin文件只包含这么多信息,代码段和常数段之间没有gap,怎么会填充0呢。
 楼主| computer00 发表于 2007-4-13 01:02 | 显示全部楼层

TO djyos: 函数的地址的确在变,

test是个函数,而addr是个全局变量,将函数test的地址赋给addr,结果在FLASH中运行和<br />把代码复制到RAM中运行时,addr的值变了.刚好相差那么多.从下面这个汇编结果也可以<br />看出来,它是将PC-0x170做为了test的地址,所以函数的地址不再是常量了。<br /><br />&nbsp;&nbsp;1015:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addr=(unsigned&nbsp;long&nbsp;int)test;&nbsp;<br />0x0000351C&nbsp;&nbsp;E24F0E17&nbsp;&nbsp;SUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R0,PC,#0x00000170<br />0x00003520&nbsp;&nbsp;E59F11A8&nbsp;&nbsp;LDR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R1,[PC,#0x01A8]<br />0x00003524&nbsp;&nbsp;E5810000&nbsp;&nbsp;STR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R0,[R1]<br />&nbsp;&nbsp;1016:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;test();&nbsp;<br />0x00003528&nbsp;&nbsp;EBFFFFA1&nbsp;&nbsp;BL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;test(0x000033B4)<br />&nbsp;&nbsp;1017:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((void(*)(void))addr)();&nbsp;<br />&nbsp;&nbsp;1018:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />0x0000352C&nbsp;&nbsp;E59F019C&nbsp;&nbsp;LDR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R0,[PC,#0x019C]<br />0x00003530&nbsp;&nbsp;E5900000&nbsp;&nbsp;LDR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R0,[R0]<br />0x00003534&nbsp;&nbsp;E1A0E00F&nbsp;&nbsp;MOV&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R14,PC<br />0x00003538&nbsp;&nbsp;E12FFF10&nbsp;&nbsp;BX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R0<br /><br /><br /><br /><br /><br />to&nbsp;mybao:&nbsp;我不太清楚HEX是如何转成bin的,因为HEX中直接有地址信息,所以中间<br />空的可以跳过.但是bin文件就是二进制文件,它是如何知道第一个字节的地址是多少的?<br />所以我认为二进制文件的第一个字节的地址为0.那么到地址0x0C000000,就有几百M那么大了。<br /><br />我把RO地址设置在0x0C000000,这样就编译通不过了,晕死,错误如下:<br />linking...<br />***&nbsp;ERROR&nbsp;L138:&nbsp;CODE&nbsp;GENERATION:&nbsp;PROBLEM&nbsp;WHEN&nbsp;PROCESSING&nbsp;INSTRUCTIONS<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CAUSE:&nbsp;&nbsp;Target&nbsp;is&nbsp;out&nbsp;of&nbsp;Range<br />&nbsp;&nbsp;&nbsp;&nbsp;SEGMENT:&nbsp;STARTUPCODE<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ADDRESS:&nbsp;01E0H<br />Program&nbsp;Size:&nbsp;data=10490&nbsp;const=3207&nbsp;code=21504<br />Target&nbsp;not&nbsp;created<br /><br /><br />今晚又试了RealView,结果还是不行,倒塌了~~~~~自己的函数调用没问题.&nbsp;问题好象出在<br />系统的库函数上,调用到这些时就会跑到FLASH中,不过具体是不是我还没弄清楚,全是汇编,<br />看了就头疼.....<br /><br />看来用让它全部产生相对跳转的代码是不大现实的了。但是把RO地址设置为RAM地址又<br />编译通不过,晕死.我现在的想法是,先编一个很小的串口程序,它可以通过串口将<br />一个bin文件加载(而这个bin文件就是我现在做的这个,把它的RO设置在RAM地址),<br />然后再跳转到这里执行。然后利用它,将自己再固化到FLASH中,然后下次复位后,<br />就把这些代码复制到RAM中,运行之...
ketp 发表于 2007-4-13 07:59 | 显示全部楼层

这是加载域和执行域的问题

在ads里是用scatter&nbsp;file搞定的,<br /><br />注意,在ads里把Read-Only&nbsp;Position&nbsp;Independent勾上。也不一定能生成位置无关代码,carm可能相似。
djyos 发表于 2007-4-13 09:56 | 显示全部楼层

to:圈圈

你注意到定义中的const修饰符了没有,如果改成下面这样呢:<br />const&nbsp;void&nbsp;(*&nbsp;const&nbsp;faddr)(void)&nbsp;=&nbsp;func;<br /><br />而且faddr是全局变量会怎么样?全局变量和局部变量是不一样的,<br /><br />局部变量的初始值是在调用时赋的值,因为编译器确实不知道变量本身的存放地址,所以只能用代码实现.编译器也不知道函数的地址,只有连接器知道,而连接器不能改变代码<br /><br />而全局变量的初始值却是编译器(准确地讲是连接器)赋的值,放在rodata段,由启动代码copy.<br /><br />不知圈圈定义的addr是全局的还是局部的,从反汇编来看应该是局部变量吧,因为全局变量不会产生下列汇编代码的:<br />0x0000351C&nbsp;&nbsp;E24F0E17&nbsp;&nbsp;SUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R0,PC,#0x00000170<br />0x00003520&nbsp;&nbsp;E59F11A8&nbsp;&nbsp;LDR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R1,[PC,#0x01A8]<br />0x00003524&nbsp;&nbsp;E5810000&nbsp;&nbsp;STR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R0,[R1]<br />
mybao 发表于 2007-4-13 10:53 | 显示全部楼层

re

to&nbsp;圈圈<br /><br />bin文件没有地址信息,跟hex不一样,RO地址设置在0x0C000000,bin文件不会把0x0000000-0xbffffff填充&nbsp;0,不会的。<br /><br />如果你还想控制ASM的生成的话,真的想偏了。<br /><br />to&nbsp;&nbsp;ketp<br /><br />在ads里是用scatter&nbsp;file搞定的,<br /><br />这个观点是错误的。在ADS里并没有给程序分配独立的加载域和执行域,加载域和执行域还是通过启动代码实现的。TI的DSP编译器CCS可以实现给程序分配真正独立的加载域和执行域,ADS并没有,scatter&nbsp;file里面的load&nbsp;region和execution&nbsp;region有误导开发者之嫌,我也被误导过。
high 发表于 2007-4-13 12:51 | 显示全部楼层

晕!

<br />some&nbsp;infomation&nbsp;from&nbsp;ads1.2&nbsp;article.<br />-----------<br />/ropi&nbsp;This&nbsp;option&nbsp;generates&nbsp;(read-only)&nbsp;position-independent&nbsp;code.&nbsp;/pic&nbsp;is&nbsp;an&nbsp;alias&nbsp;for&nbsp;this&nbsp;option.&nbsp;If&nbsp;this&nbsp;option&nbsp;is&nbsp;selected&nbsp;the&nbsp;compiler:<br /><br />&nbsp;:&nbsp;addresses&nbsp;read-only&nbsp;code&nbsp;and&nbsp;data&nbsp;pc-relative<br />&nbsp;:&nbsp;sets&nbsp;the&nbsp;Position&nbsp;Independent&nbsp;(PI)&nbsp;attribute&nbsp;on&nbsp;read-only&nbsp;output&nbsp;<br />sections.<br /><br />Note<br />&nbsp;The&nbsp;ARM&nbsp;tools&nbsp;cannot&nbsp;determine&nbsp;if&nbsp;the&nbsp;final&nbsp;output&nbsp;image&nbsp;will&nbsp;be&nbsp;<br />Read-Only&nbsp;Position&nbsp;Independent&nbsp;(ROPI)&nbsp;until&nbsp;the&nbsp;linker&nbsp;finishes&nbsp;<br />processing&nbsp;input&nbsp;sections.&nbsp;This&nbsp;means&nbsp;that&nbsp;the&nbsp;linker&nbsp;might&nbsp;emit&nbsp;ROPI&nbsp;<br />error&nbsp;messages,&nbsp;even&nbsp;though&nbsp;you&nbsp;have&nbsp;selected&nbsp;this&nbsp;option.
 楼主| computer00 发表于 2007-4-13 13:18 | 显示全部楼层

TO djyos: 我前面写得很清楚,addr是全局变量

0x0000351C&nbsp;&nbsp;E24F0E17&nbsp;&nbsp;SUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R0,PC,#0x00000170&nbsp;&nbsp;//取得函数的地址值放入R0中<br />0x00003520&nbsp;&nbsp;E59F11A8&nbsp;&nbsp;LDR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R1,[PC,#0x01A8]&nbsp;&nbsp;&nbsp;//取得addr这个变量的地址放入R1中<br />0x00003524&nbsp;&nbsp;E5810000&nbsp;&nbsp;STR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R0,[R1]&nbsp;//将函数地址写回到addr变量的地址中<br /><br /><br />全局变量才会产生这样的代码,将结果写回到RAM中。如果我用局部变量的话,它是不会<br />压写回RAM的,而直接把这个变量放在寄存器中(我当时编译时它是在放在R7中),<br />然后我将代码复制到RAM中运行,就看不到局部变量addr的值了,我才将addr改成<br />全局变量的,这样任何时刻都可以查看它的值.结果在不同的地方运行,它的值就跟着变化.<br /><br />如果照你这个const&nbsp;void&nbsp;(*&nbsp;const&nbsp;faddr)(void)&nbsp;=&nbsp;func;这么写,我下面就没办法<br />在运行中去取函数地址了,因为是常量,编译器会不让你修改它的值。由于初始化程序<br />在FLASH中,这时的地址肯定是在FLASH中。只有在程序运行过程中,取得函数地址才能反应出实际的情况.<br />实际上函数名的值已经变了。<br /><br /><br /><br />你看我将RO地址设置在0x0C000000时,产生的HEX文件:<br /><br /><br /><br />:02000004<font color=#FF0000>0000</font>FA&nbsp;&nbsp;&nbsp;//地址高16位为0<br />:1000000018F09FE518F09FE518F09FE518F09FE5C0<br />.....省略.......<br />:100200002800F801E43D000CE4010000E9010000D1<br />:02000004<font color=#FF0000>0C00</font>EE&nbsp;&nbsp;&nbsp;&nbsp;//地址高16位为0x0C00<br />:0F00000050726F6772616D202578206F6B0A0058<br />:06001000FFFFFFFFFFFFF0<br /><br /><br />从这个产生的代码来看,我将RO设置在0x0C000000,那么前面的启动代码的地址就<br />从地址0开始放,然后再跳到初始化代码以及C代码,从初始化代码后面的地址就是<br />0x0C000000了。它这样做的目的应该保证复位后代码正常运行。<br /><br />那现在我的代码即有地址0,又有地址0x0C00000,如果中间不填充一些什么的话,<br />那又如何知道后面的代码是在0x0c000000呢?不过我用51的hex2bin的软件,<br />转换之后,它就忽略了前面那段了.<br /><br /><br /><br />我现在的想法就是,先把这个程序的RO地址设置在RAM,编译之,然后把产生的HEX文件<br />前面的部分删除,只保留后面的RAM部分,然后转换成bin文件.之后再写一个小的加载<br />程序,将这个bin文件通过串口加载到RAM中,然后运行之.这时就可以利用这个程序,<br />把自己固化在FLASH中,并且再搞个启动代码也烧到FLASH中,那么下次开机时,<br />由这个启动代码将FLASH的内容复制到RAM中,然后运行之,这样就可以搞定了。<br />不过蛮晕菜的,要搞这么多步骤......<br /><br /><br /><br />
wlq_9 发表于 2007-4-13 13:43 | 显示全部楼层

先在RAM里运行bootloader

再把代码写到flash中去,这样就可以解决地址问题。<br />要不用IAR,利用它提供的framework,自己写flashloader,把原本编译到A地址的数据写到B地址,这样就可以一步完成。
mybao 发表于 2007-4-13 13:44 | 显示全部楼层

re

RO设置在0x0C000000,&nbsp;&nbsp;&nbsp;启动代码的地址怎么会从地址0开始放呢?<br /><br />你不至于用汇编伪指令强行把启动代码定位到&nbsp;0&nbsp;吧?<br /><br />
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部