搜索
bottom↓
回复: 54

IAR STM32 函数和变量的绝对地址定位

  [复制链接]

出0入0汤圆

发表于 2012-5-31 15:05:02 | 显示全部楼层 |阅读模式

    昨天我突然冒出个想法,能否利用函数和变量的绝对定位,实现程序的模块化更新。

  也就是说,如果我要改变某个函数,只需要更新flash里面一个局部,也许只需要更新几百个字节,而无须重新下载整个上百K的程序。

  经过查找资料和反复实验,终于实现了,现总结如下:

  1) 把函数定位在FLASH高端的指定位置,以后更新,只更新那小块地方就可以了。

  方法一:

    IAR里面进行函数定位, 必须要在.icf里面,进行定义。

   void sendstr(unsigned *buf,unsigned short  len) @".sendstr"
   {
    ....
   }

   .icf文件,加入这样一句:
  place at address mem:0x08017000 { readonly section .sendstr};

  方法二)  把要更新的函数,单独放在一个.c文件中,然后再.icf文件里面,对该文件进行定位:
  test.c

  int f1(int a,int b){
  if(a>0){
   return (a+b)*1;
  }
  else return 0;
}
  int f2(int a,int b){
  if(a>0){
   return (a+b)*1;
  }
  else return 0;
}

那么在 .icf文件中,这样写:
place at address mem:0x08018000 { section .text object test.o };
编译完成后, f1就定位在0x08018000 处了,当然f2也紧跟在f1后面。整个test.c文件的所有函数,都在0x08018000 之后。

如果有多个函数需要单独更新,建议采用第二种方式, 只需要对c文件编译后的地址定位,那么该c文件的所有函数都定位了。

绝对定位的函数,只要指定了地址,那么在flash里面的位置就是固定的。


即使是两个不同的工程,比如第一个工程为实际工程,里面有所有的工程文件,  第二个工程为更新专用工程,里面仅仅只有test.c文件,里面的函数是同名的,定位地址与第一个工程也一样。

那么这样编译后,第二个工程里面的固件片断,是可以用来更新一个工程的固件的。

这样还可以派生出一个很怪的用法:
我可以把更新专用工程,公布给别人,他只需要在test.c里面,编写函数的具体内容。 然后一样可以更新产品的固件。
真正的实际工程,是不需要公布的。

以上是对函数的绝对定位处理。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------

2)变量定位

变量绝对定位:
__no_init char array1[100]@0x2000B000;

变量绝对定位,无须修改.icf,直接指定

这个array1就定位在RAM中的0x2000B000处

常量绝对定位:
const char str1[8]@".MYSEG"="test11!!";
常量绝对定位,需要改.icf文件:
place at address mem:0x08018500 { readonly section .MYSEG};

------------------------------------------------------------------------------------------------------------------------------------------

3)跨工程固件更新注意事项:

固件更新区的绝对定位的函数,不能随意调用其他库函数,那些被调用的函数也必须是绝对定位的。否则跨工程更新固件,会导致失败,因为被调用的函数在不同工程里,动态连接到的位置不同。

但是这个可以解决:被调用的函数,在两边工程都申明的绝对地址,并且在非固件更新区(就是两边工程的固件里,这些被调用函数的位置都一样,只需要函数名和地址一样即可,函数内部可以不同)。那么被这些调用的函数内,可以随意调用其他函数,如printf ,strcpy等库函数了。

绝对定位的函数,如果要使用常量,那么被使用的常量也必须是绝对定位的。否则跨工程更新固件,会导致失败。

绝对定位的函数,如果要使用全局变量,那么被使用的常量也必须是绝对定位的。否则跨工程更新固件,会导致失败。  而局部变量则不受此限制。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

出0入0汤圆

 楼主| 发表于 2012-5-31 15:05:59 | 显示全部楼层
###############################################################################
#                                                                             #
# IAR ELF Linker V5.50.0.51878/W32 for ARM              31/May/2012  12:50:09 #
# Copyright (C) 2007-2010 IAR Systems AB.                                     #
#                                                                             #
#    Output file  =  E:\stm32\software4.45.2\Debug\Exe\software.out           #
#    Map file     =  E:\stm32\software4.45.2\Debug\List\software.map          #
#    Command line =  E:\stm32\software4.45.2\Debug\Obj\main.o                 #
#                    E:\stm32\software4.45.2\Debug\Obj\test.o -o              #
#                    E:\stm32\software4.45.2\Debug\Exe\software.out --map     #
#                    E:\stm32\software4.45.2\Debug\List\software.map          #
#                    --config E:\stm32\software4.45.2\stm32f10x_flash.icf     #
#                    --semihosting --entry __iar_program_start                #
#                                                                             #
#                                                                             #
###############################################################################

*******************************************************************************
*** PLACEMENT SUMMARY
***

"A1":  place at 0x08004000 { ro section .intvec };
"A2":  place at 0x08017000 { ro section .sendstr };
"A3":  place at 0x08018500 { ro section .MYSEG };
"A4":  place at 0x08018000 { object test.o section .text };
"P1":  place in [from 0x08004000 to 0x08020000] { ro };
"P2":  place in [from 0x20000000 to 0x2000bfff] {
          rw, block CSTACK, block HEAP };

  Section            Kind        Address   Size  Object
  -------            ----        -------   ----  ------
"A1":                                      0x40
  .intvec            ro code  0x08004000   0x40  vector_table_M.o [4]
                            - 0x08004040   0x40

"P1":                                     0x100
  .text              ro code  0x08004040   0x30  copy_init3.o [4]
  .text              ro code  0x08004070   0x2c  data_init3.o [4]
  .text              ro code  0x0800409c   0x28  iarttio.o [5]
  .iar.init_table    const    0x080040c4   0x14  - Linker created -
  .text              ro code  0x080040d8   0x16  cmain.o [4]
  .text              ro code  0x080040f0   0x14  exit.o [5]
  .text              ro code  0x08004104    0xc  cstartup_M.o [4]
  .text              ro code  0x08004110    0xa  cexit.o [4]
  .text              ro code  0x0800411a    0xa  main.o [1]
  .text              ro code  0x08004124    0x8  XShttio.o [3]
  .text              ro code  0x0800412c    0x6  exit.o [3]
  .text              ro code  0x08004132    0x4  low_level_init.o [3]
  .text              ro code  0x08004136    0x2  vector_table_M.o [4]
  Initializer bytes  ro data  0x08004138    0x8  <for P2 s0>
                            - 0x08004140  0x100

"A2":                                       0x2
  .sendstr           ro code  0x08017000    0x2  main.o [1]
                            - 0x08017002    0x2

"A4":                                      0x54
  .text              ro code  0x08018000   0x54  test.o [1]
                            - 0x08018054   0x54

"A3":                                      0x10
  .MYSEG             const    0x08018500   0x10  test.o [1]
                            - 0x08018510   0x10

"P2", part 1 of 2:                        0x400
  CSTACK                      0x20000000  0x400  <Block>
    CSTACK           uninit   0x20000000  0x400  <Block tail>
                            - 0x20000400  0x400

"P2", part 2 of 2:                          0x8
  P2 s0                       0x20000400    0x8  <Init block>
    .data            inited   0x20000400    0x8  XShttio.o [3]
                            - 0x20000408    0x8


*******************************************************************************
*** INIT TABLE
***

          Address     Size
          -------     ----
Copy (__iar_copy_init3)
    1 source range, total size 0x8 (100% of destination):
          0x08004138   0x8
    1 destination range, total size 0x8:
          0x20000400   0x8


*******************************************************************************
*** MODULE SUMMARY
***

    Module            ro code  ro data  rw data
    ------            -------  -------  -------
E:\stm32\software4.45.2\Debug\Obj: [1]
    main.o                 12
    test.o                 84       16
    -------------------------------------------
    Total:                 96       16

command line: [2]
    -------------------------------------------
    Total:

dl7M_tl_in.a: [3]
    XShttio.o               8        8        8
    exit.o                  6
    low_level_init.o        4
    -------------------------------------------
    Total:                 18        8        8

rt7M_tl.a: [4]
    cexit.o                10
    cmain.o                22
    copy_init3.o           48
    cstartup_M.o           12
    data_init3.o           44
    vector_table_M.o       66
    -------------------------------------------
    Total:                202

shb_l.a: [5]
    exit.o                 20
    iarttio.o              40
    -------------------------------------------
    Total:                 60

    Gaps                    2
    Linker created                  20    1 024
-----------------------------------------------
    Grand Total:          378       44    1 032


*******************************************************************************
*** ENTRY LIST
***

Entry                    Address  Size  Type      Object
-----                    -------  ----  ----      ------
BusFault_Handler      0x08004137        Code  Wk  vector_table_M.o [4]
CSTACK$$Base          0x20000000         --   Gb  - Linker created -
CSTACK$$Limit         0x20000400         --   Gb  - Linker created -
DebugMon_Handler      0x08004137        Code  Wk  vector_table_M.o [4]
HardFault_Handler     0x08004137        Code  Wk  vector_table_M.o [4]
MemManage_Handler     0x08004137        Code  Wk  vector_table_M.o [4]
NMI_Handler           0x08004137        Code  Wk  vector_table_M.o [4]
PendSV_Handler        0x08004137        Code  Wk  vector_table_M.o [4]
Region$$Table$$Base   0x080040c4         --   Gb  - Linker created -
Region$$Table$$Limit  0x080040d8         --   Gb  - Linker created -
SVC_Handler           0x08004137        Code  Wk  vector_table_M.o [4]
SysTick_Handler       0x08004137        Code  Wk  vector_table_M.o [4]
UsageFault_Handler    0x08004137        Code  Wk  vector_table_M.o [4]
__cmain               0x080040d9        Code  Gb  cmain.o [4]
__exit                0x080040f1  0x14  Code  Gb  exit.o [5]
__iar_close_ttio      0x0800409d  0x26  Code  Gb  iarttio.o [5]
__iar_copy_init3      0x08004041  0x30  Code  Gb  copy_init3.o [4]
__iar_data_init3      0x08004071  0x2c  Code  Gb  data_init3.o [4]
__iar_lookup_ttioh    0x08004125   0x8  Code  Gb  XShttio.o [3]
__iar_program_start   0x08004105        Code  Gb  cstartup_M.o [4]
__iar_ttio_handles    0x20000400   0x8  Data  Lc  XShttio.o [3]
__low_level_init      0x08004133   0x4  Code  Gb  low_level_init.o [3]
__vector_table        0x08004000        Data  Gb  vector_table_M.o [4]
_call_main            0x080040e5        Code  Gb  cmain.o [4]
_exit                 0x08004111        Code  Gb  cexit.o [4]
_main                 0x080040eb        Code  Gb  cmain.o [4]
exit                  0x0800412d   0x6  Code  Gb  exit.o [3]
f1                    0x08018049   0xc  Code  Gb  test.o [1]
main                  0x0800411b   0xa  Code  Gb  main.o [1]
sendstr               0x08017001   0x2  Code  Gb  main.o [1]
str1                  0x08018500   0x8  Data  Gb  test.o [1]
str2                  0x08018508   0x8  Data  Gb  test.o [1]
test                  0x08018001  0x44  Code  Gb  test.o [1]


[1] = E:\stm32\software4.45.2\Debug\Obj
[2] = command line
[3] = dl7M_tl_in.a
[4] = rt7M_tl.a
[5] = shb_l.a

    378 bytes of readonly  code memory
     44 bytes of readonly  data memory
  1 032 bytes of readwrite data memory

Errors: none
Warnings: none

出0入0汤圆

 楼主| 发表于 2012-5-31 15:06:30 | 显示全部楼层
这是.icf文件

/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x08004000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__   = 0x08004000;
define symbol __ICFEDIT_region_ROM_end__     = 0x08020000;
define symbol __ICFEDIT_region_RAM_start__   = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__     = 0x2000BFFF;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__   = 0x400;
define symbol __ICFEDIT_size_heap__     = 0x200;
/**** End of ICF editor section. ###ICF###*/


define memory mem with size = 4G;
define region ROM_region   = mem:[from __ICFEDIT_region_ROM_start__   to __ICFEDIT_region_ROM_end__];
define region RAM_region   = mem:[from __ICFEDIT_region_RAM_start__   to __ICFEDIT_region_RAM_end__];

define block CSTACK    with alignment = 8, size = __ICFEDIT_size_cstack__   { };
define block HEAP      with alignment = 8, size = __ICFEDIT_size_heap__     { };

initialize by copy { readwrite };
do not initialize  { section .noinit };

place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };

place at address mem:0x08017000 { readonly section .sendstr};
place at address mem:0x08018500 { readonly section .MYSEG};

place at address mem:0x08018000 { section .text object test.o };

place in ROM_region   { readonly };
place in RAM_region   { readwrite,
                        block CSTACK, block HEAP };

出0入0汤圆

 楼主| 发表于 2012-5-31 15:07:04 | 显示全部楼层
main.c

/* Includes ------------------------------------------------------------------*/
//#include "stm32f10x.h"
#include "string.h"
#include "stdio.h"

void sendstr(unsigned *buf,unsigned short  len) @".sendstr"
{
}

extern void test(void);
extern void main1(void);
int main(void)
{
     test();
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

/**
  * @}
  */

/**
  * @}
  */

/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/

出0入0汤圆

 楼主| 发表于 2012-5-31 15:07:23 | 显示全部楼层
test.c

//__no_init char array1[100]@0x2000B000;

//char array1[100];

const char str1[8]@".MYSEG"="test11!!";
const char str2[8]@".MYSEG"="test66!!";


int f1(int a,int b);
void test(void)// @".test" //MYSEGMENT段可在XCL中开辟
{
    char arrayx[150];  
    char array1[150];
    int i,a,b,c;
    for (i=0;i<8;i++){
      array1[i]=str1[i];      
      arrayx[i]=str2[i];      
    }
    a=1;
    b=2;
    c=f1(a,b);
    for (i=0;i<c;i++) {
      sendstr(array1,8);   
      sendstr(arrayx,8);   
    }
}

int f1(int a,int b){
  if(a>0){
   return (a+b)*1;
  }
  else return 0;
}

出0入8汤圆

发表于 2012-5-31 15:18:41 | 显示全部楼层
这个有意思

出0入0汤圆

发表于 2012-5-31 15:22:38 | 显示全部楼层
学习了

出0入0汤圆

发表于 2012-5-31 23:11:59 来自手机 | 显示全部楼层
gcc支持重定位

出0入0汤圆

发表于 2012-6-1 00:26:41 | 显示全部楼层
好东西MARK

出0入0汤圆

发表于 2012-12-11 16:35:54 | 显示全部楼层
也是这么用的,不过没有lz总结得好,一段时间后新程序用到时,还需要翻出老程序仔细查

出0入0汤圆

发表于 2012-12-17 11:06:12 | 显示全部楼层
标记                                       

出0入0汤圆

发表于 2013-2-21 14:19:34 | 显示全部楼层
mark一下。。。

出0入0汤圆

发表于 2013-2-22 17:47:51 | 显示全部楼层
MDK能不能实现呢?

出0入0汤圆

发表于 2013-2-22 18:53:31 | 显示全部楼层
对于你的第三点,cortex和其他arm处理器都提供了一种特殊的中断。。。。Software Interrupt (SVC)
你只要把系统服务都通过svc来调用,那么就不需要知道调用的实际地址了。。。
当然你也可以在固定的位置放一个函数指针表来手动做这个,调用系统服务的时候从函数指针表上获得当前版本的函数的绝对定位

出50入8汤圆

发表于 2013-2-23 09:32:50 来自手机 | 显示全部楼层
顶楼主 很实用的技术贴

出0入0汤圆

发表于 2013-3-14 17:41:04 | 显示全部楼层
MarkMark!!!

出0入0汤圆

发表于 2013-3-28 20:59:29 | 显示全部楼层
正好也用到常量定位

出0入0汤圆

发表于 2013-7-9 00:51:53 来自手机 | 显示全部楼层
总结的相当好,学习了

出0入0汤圆

发表于 2013-7-9 07:55:02 来自手机 | 显示全部楼层
这个很好,学习一下

出0入0汤圆

发表于 2013-7-10 02:48:08 | 显示全部楼层
Mark 常量定位

出0入0汤圆

发表于 2013-8-5 14:04:20 | 显示全部楼层
很好的资料,学习了,同问MDK的有效方案。

出0入0汤圆

发表于 2013-8-5 15:09:40 | 显示全部楼层
和动态链接库一个道理

出0入0汤圆

发表于 2013-9-13 11:31:47 | 显示全部楼层
楼主太好了在你的帮助下我实验成功了,之前的看的资料都太隐晦了,你这个讲的太好了

出0入0汤圆

发表于 2013-9-13 13:17:15 来自手机 | 显示全部楼层
mark,谢谢分享

出0入0汤圆

发表于 2013-9-19 08:57:09 | 显示全部楼层
绝对定位很有用

出0入0汤圆

发表于 2013-9-21 02:07:58 | 显示全部楼层
mark,iar函数编译定位绝对地址

出0入0汤圆

发表于 2013-9-21 04:20:47 | 显示全部楼层
似乎并不安全....

出0入0汤圆

发表于 2013-9-21 04:28:25 | 显示全部楼层
如果要安全的话,你可能需要自己弄一套工具.
但是如果真的要搞一套工具的话,还不如自己弄个LINKER.
楼主你不如眼光放远点.......

出0入0汤圆

发表于 2013-9-21 11:13:14 | 显示全部楼层
想法很不错,不过感觉实用价值并不大,但是仍然支持一下

出10入95汤圆

发表于 2013-9-26 11:21:35 | 显示全部楼层
帖子不错!
请教楼主:如果是跨工程应用,怎么保证堆栈的连续性呢?

出0入0汤圆

发表于 2013-10-2 16:31:42 来自手机 | 显示全部楼层
不错收藏中   

出0入0汤圆

发表于 2013-10-18 10:43:21 | 显示全部楼层
谢谢分享!相当有用!

出0入0汤圆

发表于 2014-1-17 17:23:11 | 显示全部楼层
马克一下!!!!

出0入0汤圆

发表于 2014-1-17 19:07:43 | 显示全部楼层
mark                                   

出0入0汤圆

发表于 2014-1-17 19:19:29 来自手机 | 显示全部楼层
这个需要功底   一般的还搞不了

出0入0汤圆

发表于 2014-2-9 06:36:45 来自手机 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2014-2-26 21:31:58 来自手机 | 显示全部楼层
楼主好,我是做工控的,用stm32做的动作板,想实现看门狗复位或说软复位后动作开关能不受影响,就是原来开着的,看门狗复位后还是开着,高手们说可以修改启动代码让软复位不初始化RAM和寄存器,我不知怎么弄,请楼主赐教,谢谢

出0入0汤圆

发表于 2014-3-13 20:00:50 | 显示全部楼层
这个牛。。。。

出0入0汤圆

发表于 2014-3-19 10:19:21 | 显示全部楼层
非常不错!

出0入0汤圆

发表于 2014-4-24 23:37:23 | 显示全部楼层
关于绝对定位,赞一个,mark!

出0入0汤圆

发表于 2014-5-31 11:07:46 | 显示全部楼层
iar 变量声明 extern  XDATA __no_init unsigned int SampleRed[SAMPLESIZE]@0x0788;总是报错;去掉定位后就可以了,不知道为什么?

Error[e46]: Undefined external "SampleRed" referred in AD ( C:\。。。

出0入0汤圆

发表于 2014-7-13 15:33:24 | 显示全部楼层
不知道有没有人在mdk下实现这样的功能?

出0入0汤圆

发表于 2014-8-11 17:07:36 | 显示全部楼层
markkkkkkkkkkkkkkkkkkkkk

出0入42汤圆

发表于 2014-8-26 11:14:43 | 显示全部楼层
楼主威武,我可以用它编写脚本了。

出0入42汤圆

发表于 2014-8-26 17:58:21 | 显示全部楼层
smset 发表于 2012-5-31 15:07
test.c

//__no_init char array1[100]@0x2000B000;

楼主,请问将地址转换成函数指针这块您是怎么处理的? 为什么我将定位的地址 强转成指针去内容转换成函数指针后,调用的时候会出错?
typedef  void (*func)(void);   
func pStm32config;

pStm32config = (func)(*((unsigned int *)0x08030000));//0x08030000是我定义的函数的绝对地址

我是这样调用的:

pStm32config();

但是会进硬错误。

出0入0汤圆

发表于 2014-11-8 13:58:43 | 显示全部楼层
不能直接定位,还是没有MDK那样灵活

出0入0汤圆

发表于 2015-3-10 16:21:00 | 显示全部楼层
MARK   。

出0入0汤圆

发表于 2015-3-10 17:13:46 | 显示全部楼层
牛逼.............

出0入0汤圆

发表于 2015-5-23 02:40:24 | 显示全部楼层
记号,学习中

出0入10汤圆

发表于 2015-12-15 18:12:25 | 显示全部楼层
我来添加多一个命令,指定C文件的所有内容到固定的地址范围之内。
define symbol __ICFEDIT_region_TEST_start__ = 0x00009800;
define symbol __ICFEDIT_region_TEST_end__   = (0x00009800+0x200-1);
define region TEST_region  = mem:[from __ICFEDIT_region_TEST_start__  to __ICFEDIT_region_TEST_end__];
place in TEST_region  {section .text object crc.o};

出0入0汤圆

发表于 2016-9-26 11:33:19 | 显示全部楼层
确实不错,不用更新整个程序了

出0入0汤圆

发表于 2019-4-26 16:04:11 | 显示全部楼层
注意事项 总结的不错,赞!

出0入0汤圆

发表于 2019-4-29 16:10:58 | 显示全部楼层
正好有个项目 是在MDK上的 不是IAR

OTP+SRAM+EEPROM.也是随时更新code,不过不是用的楼主的办法

我是开辟固定的位置作为函数指针,刷新这个值,就可以自由跳转了。

这一切都是 OTP写了一次就不能再写了 做的孽

出0入0汤圆

发表于 2019-5-8 09:57:09 | 显示全部楼层

研究的好深,厉害
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-6 07:55

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表