查看: 10571|回复: 11

[原创] 【经验分享】OTA bootloader swap与Rollback功能

[复制链接]

该用户从未签到

715

主题

6374

帖子

0

超级版主

Rank: 8Rank: 8

积分
25182
最后登录
2025-8-12
发表于 2021-7-19 17:23:25 | 显示全部楼层 |阅读模式
本帖最后由 小恩GG 于 2021-7-19 17:26 编辑

【经验分享】OTAbootloader swap与Rollback功能

一 文档介绍

   官方RT1060 SDK 代码提供了ota_bootloader, 可以供客户实现代码的在线升级,RT10xx OTA bootloader主要功能有两个:

1. 在flash里面实现ISP下载代码到外部flash

2. 提供API给用户,实现不同APP的 swap与rollback

   之前分享了几篇经验分享,详细讲解了使用ISP下载代码的情况:



本篇文章主要讲解OTA的memory结构,相关常用API,swap/roll back功能,并且下载APP1,APP2到不同的区域,利用uart输入字符去选择具体的swap运行APP2,还是roll back为APP1运行。


二 ota bootloader原理

2.1 OTA boot loader分区情况

1.jpg

图1

上述分区情况是在外部QSPI flash,大小8Mbyte的情况下。

OTA bootloader: RT SDK ota bootloader 代码

Boot meta 0: 包含了三个partition的起始地址,大小等信息, ISP的外设信息.

Boot meta 1: 包含了三个partition的起始地址,大小等信息.,ISP的外设信息.

Swap meta 0: Bootloader根据meta中的数据进行swap操作

Swap meta 1: Bootloader根据meta中的数据进行swap操作

Partition 1: APP1存放位置

Partition 2: APP2存放位置

Scratch part: APP1 backup位置, 0X60441000前面足够放APP1并且是整数倍sector大小的空间位置。

User data: 用户数据


2.2 swap 和rollback原理

2.jpg

图2

   Partition1和partition2的APP需要带有满足bootloader的ota_header, bootloader 会对APP进行CRC校验,通过才会boot,否则会进入ISP。

  调用API获取partition2的信息,将需要更新的image放到partition2中,这个image必须要具有合法的header,否则不能swap。

   Swap先将partition2scratch位置擦除,然后把partition1的代码写到scratch中,擦除partition1位置,并且将partition2代码写到Partition1位置。

    Rollback, 重新运行之前的APP1,擦除partition2位置,把partition1代码写回partition2位置, 擦除partition1位置,拷贝parition2 scratch位置的代码写到partition1.


2.3 boot meta 和 swap meta

boot_meta 0adddr: 0x0x6003c000 size: 0x0x0000020c

boot_meta 1adddr: 0x0x6003d000 size: 0x0x0000020c



2.3.1 Boot meta

OTA bootloader可以从两个地址获取boot Meta数据,当两个地址存放的meta都是合法时(tag要为('B', 'L', 'M', 'T') // 0x42, 0x4c,0x4d, 0x54),bootloader选择version大的meta。如果两个地方都没有合法的meta在,bootloader会将default的bootmeta值烧写到第一个地址处。

Bootmeta中包含了三个partition的起始地址,大小等信息。SDK demo可以通过调用Bootloader的API找到partition的信息,从而进行image的烧写。

另外boot meta还包含了ISP的peripheral,启动后跳转到APP的等待时间等信息(默认5s)。具体参见如下结构体:

  1. //!@brief Partition information table definitions
  2. typedef struct
  3. {
  4.     uint32_t start;        //!< Start address of the partition
  5.     uint32_t size;         //!< Size of the partition
  6.     uint32_t image_state;  //!< Active/ReadyForTest/UnderTest
  7.     uint32_t attribute;    //!< Partition Attribute - Defined for futher use
  8.     uint32_t reserved[12]; //!< Reserved for future use
  9. } partition_t;

  10. //!@brief Bootloader meta data structure
  11. typedef struct
  12. {
  13.     struct
  14.     {
  15.         uint32_t wdTimeout;
  16.         uint32_t periphDetectTimeout;
  17.         uint32_t enabledPeripherals;
  18.         uint32_t reserved[12];
  19.     } features;

  20.     partition_t partition[kPartition_Max];
  21.     uint32_t meta_version;
  22.     uint32_t patition_entries;
  23.     uint32_t reserved0;
  24.     uint32_t tag;
  25. } bootloader_meta_t;
复制代码


2.3.2 swap meta

  OTA bootloader 会从两个地方获取swap meta,如果都非法的话,bootloader会设置一个default值用于进入ISP,这个值最终会写到meta 0对应的地址中(0x6003e000)。如果两个都合法,bootloader会选择version大的meta。

Bootloader根据meta中的数据进行swap操作,某些情况下,reset后meta中的数据会动态修改。主要的行为体现在swap_type这个变量中.

Swap_type的说明如下:

  • kSwapType_ReadyForTest :reset后进行swap


修改meta中的swap_type为kSwapType_Test.

再次reset后,由于meta中的swap type为kSwapType_Test.Bootloader根据kSwapType_Test.的操作规则进行一次rollback。

2. kSwapType_Test: reset后进行rollback

    这个参数仅供bootloader内部使用,作用就是进行image的rollback

3. kSwapType_Rollback

    Bootloader会在meta中写入kSwapType_Test,reset后bootloader按照kSwapType_Test进行操作

4. kSwapType_Permanent

    Reset后修改meta为kSwapType_Permanent,永远从partition1 boot

结构体如下:

  1. //!@brief Swap progress definitions
  2. typedef struct
  3. {
  4.     uint32_t swap_offset;    //!< Current swap offset
  5.     uint32_t scratch_size;   //!< The scratch area size during current swapping
  6.     uint32_t swap_status;    // 1 : A -> B scratch,  2 : B -> A
  7.     uint32_t remaining_size; //!< Remaining size to be swapped
  8. } swap_progress_t;

  9. typedef struct
  10. {
  11.     uint32_t size;
  12.     uint32_t active_flag;
  13. } image_info_t;

  14. //!@brief Swap meta information, used for the swapping operation
  15. typedef struct
  16. {
  17.     image_info_t image_info[2]; //!< Image info table
  18. #if !defined(BL_FEATURE_HARDWARE_SWAP_SUPPORTED) || (BL_FEATURE_HARDWARE_SWAP_SUPPORTED == 0)
  19.     swap_progress_t swap_progress; //!< Swap progress
  20. #endif
  21.     uint32_t swap_type;    //!< Swap type
  22.     uint32_t copy_status;  //!< Copy status
  23.     uint32_t confirm_info; //!< Confirm Information
  24.     uint32_t meta_version; //!< Meta version
  25.     uint32_t reserved[7];  //!< Reserved for future use
  26.     uint32_t tag;          //!< Swap meta tag
  27. } swap_meta_t;//!@brief Swap progress definitions
  28. typedef struct
  29. {
  30.     uint32_t swap_offset;    //!< Current swap offset
  31.     uint32_t scratch_size;   //!< The scratch area size during current swapping
  32.     uint32_t swap_status;    // 1 : A -> B scratch,  2 : B -> A
  33.     uint32_t remaining_size; //!< Remaining size to be swapped
  34. } swap_progress_t;

  35. typedef struct
  36. {
  37.     uint32_t size;
  38.     uint32_t active_flag;
  39. } image_info_t;

  40. //!@brief Swap meta information, used for the swapping operation
  41. typedef struct
  42. {
  43.     image_info_t image_info[2]; //!< Image info table
  44. #if !defined(BL_FEATURE_HARDWARE_SWAP_SUPPORTED) || (BL_FEATURE_HARDWARE_SWAP_SUPPORTED == 0)
  45.     swap_progress_t swap_progress; //!< Swap progress
  46. #endif
  47.     uint32_t swap_type;    //!< Swap type
  48.     uint32_t copy_status;  //!< Copy status
  49.     uint32_t confirm_info; //!< Confirm Information
  50.     uint32_t meta_version; //!< Meta version
  51.     uint32_t reserved[7];  //!< Reserved for future use
  52.     uint32_t tag;          //!< Swap meta tag
  53. } swap_meta_t;
复制代码


2.4 常用API

     Bootloader对外提供API进行操作。SDK常用的API如下

2.4.1 update_image_state

更新swap meta中的数据,更新之前会校验partition1中image的合法性,如果没有合法的image,swap meta中的数据不会更新,返回failure

2.4.2 get_update_partition_info

获取partition的信息,从而指定需要更新的image的写入地址

2.4.3 get_image_state

获取当前bootimage的状态

None/permanent – 表示image不会再swap

UnderTest – 表示reset后会进行rollback操作


三 操作步骤与实现

  本次操作,准备两个APP:APP1(起始地址0X60040000)和APP2(起始地址0X60240000) bin文件, 分别使用ISP USB HID下载到partition1和partition2, 第一次上电,默认运行APP1,然后通过APP1里面的串口选择实现swap 和rollback功能。

3.1 APP准备

实现代码如下:

  1. int main(void)
  2. {
  3.     char ch;
  4.     status_t status;
  5.     /* Board pin init */
  6.     BOARD_InitPins();
  7.     BOARD_InitBootClocks();
  8.     /* Update the core clock */
  9.     SystemCoreClockUpdate();
  10.     BOARD_InitDebugConsole();

  11.     PRINTF("\r\n------------------hello world + led blinky demo 2.------------------\r\n");

  12.     PRINTF("\r\nOTA bootloader test...\r\n"
  13.         "1 - ReadyForTest\r\n"
  14.         "3 - kSwapType_Permanent\r\n"
  15.         "4 - kSwapType_Rollback\r\n"
  16.         "5 - show image state\r\n"
  17.             "6 - led blinking for 5times\r\n"
  18.         "r - NVIC reset\r\n");
  19.     // show swap state in swap meta
  20.     get_image_swap_state();
  21.     /* Set systick reload value to generate 1ms interrupt */
  22.     if (SysTick_Config(SystemCoreClock / 1000U))
  23.     {
  24.         while (1)
  25.         {
  26.         }
  27.     }



  28.     while(1)
  29.     {
  30.         ch = GETCHAR();
  31.         switch(ch)
  32.         {
  33.           case '1':
  34.             status = bl_update_image_state(kSwapType_ReadyForTest);
  35.             PRINTF("update_image_state to kSwapType_ReadyForTest status: %i\n", status);
  36.             if (status != 0)
  37.                PRINTF("update_image_state(kSwapType_ReadyForTest): failed\n");
  38.             else
  39.                NVIC_SystemReset();
  40.             break;

  41.           case '3':
  42.             status = bl_update_image_state(kSwapType_Permanent);
  43.             PRINTF("update_image_state to kSwapType_Permanent status: %i\n", status);
  44.             if (status != 0)
  45.                PRINTF("update_image_state(kSwapType_Permanent): failed\n");
  46.             else
  47.                NVIC_SystemReset();
  48.             break;

  49.           case '4':
  50.             status = bl_update_image_state(4); // current API code in SDK does not include enumerate data for this, use 4 instead
  51.             PRINTF("update_image_state to kSwapType_Rollback status: %i\n", status);
  52.             if (status != 0)
  53.                PRINTF("update_image_state(kSwapType_Rollback): failed\n");
  54.             else
  55.                NVIC_SystemReset();
  56.             break;

  57.           case '5':
  58.               // show swap state in swap meta
  59.               get_image_swap_state();
  60.               break;
  61.           case '6':
  62.                   Led_blink10times();
  63.                   break;

  64.           case 'r':
  65.                NVIC_SystemReset();
  66.               break;

  67.         }
  68.     }

  69. }
复制代码

准备的APP需要注意添加正确的ota_header在前0X400位置,否则不能boot或者不能实现swap。

  1. const boot_image_header_t ota_header = {
  2.     .tag           = IMG_HDR_TAG,
  3.     .load_addr     = ((uint32_t)&ota_header) + BL_IMG_HEADER_SIZE,
  4.     .image_type    = IMG_TYPE_XIP,
  5.     .image_size    = 0,
  6.     .algorithm     = IMG_CHK_ALG_CRC32,
  7.     .header_size   = BL_IMG_HEADER_SIZE,
  8.     .image_version = 0,
  9.     .checksum      = {0xFFFFFFFF},
  10. };
复制代码


给出一个正确的样本:

3.jpg

图3

这里注意的是,之前的经验分享添加的ota_header只能实现APP1的boot,不能实现swap功能,是因为没有添加正确的image size和checksum值。

所以本文给出一个小软件image_header_padding.exe,可以将输入不带ota_header自动添加正确带有image大小和crc值的前0X400头部。


3.2 操作步骤

准备好的不带ota_header的APP1 evkmimxrt1060_APP1_0X60040400.bin, APP2 image evkmimxrt1060_APP2_0X60240400.bin,blhost.exe,image_header_padding.exe放到一个文件夹下面,APP1,APP2几乎一样,只是打印的结果一个是版本1,一个是版本2:

hello world + led blinky demo 1

hello world + led blinky demo 2

运行如下bat的命令:

  1. image_header_padding.exe evkmimxrt1060_APP1_0X60040400.bin 0x60040400
  2. sleep 20

  3. blhost.exe -t 50000 -u 0x15a2,0x0073 -j -- get-property 1 0
  4. sleep 20

  5. blhost.exe -u -t 1000000 -- flash-erase-region 0x6003c000 0x4000
  6. sleep 50

  7. blhost -u -t 5000 -- flash-erase-region 0x60040000 0x10000
  8. sleep 50

  9. blhost -u -t 5000 -- write-memory 0x60040000 boot_img_crc32.bin
  10. sleep 100

  11. image_header_padding.exe evkmimxrt1060_APP2_0X60240400.bin 0x60040400
  12. sleep 20

  13. blhost -u -t 5000 -- flash-erase-region 0x60240000 0x10000
  14. sleep 50

  15. blhost -u -t 5000 -- flash-erase-region 0x6043b000 0x10000
  16. sleep 50

  17. blhost -u -t 5000 -- write-memory 0x60240000 boot_img_crc32.bin
  18. sleep 100

  19. pause
复制代码


主要功能是生成APP1对应带头的image,擦除partition1位置,写入APP1。 生成APP2对应带头的image,擦除partition2和scratch位置,写入APP2。

运行bat在下载ota_bootloader并且复位5秒内,运行ISP连接:

blhost.exe -t 50000 -u 0x15a2,0x0073 -j --get-property 1 0

ota_bootloader可以直接通过IDE下载到0X60000000开始的bootloader区域。


3.3 测试结果

4.jpg

图4

从测试结果可以看到,第一次boot了APP1,imagestate: none

输入1,进行swap,可以发现APP2运行,image state: underTest

输入3, 选择permenant,复位后可以发现,运行的依旧是APP2, image state: permenant

输入4, 选择rollback,复位后可以看到运行APP1,image states:none

自此,完成了swap以及rollback功能的准确运行。

另外输入6,可以查看带有SDRAM的led blinky功能可以准确工作,再一次验证了之前ota_bootloader添加DCD的运行准确。

测试log


  1. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>image_header_padding.exe evkmimxrt1060_APP1_0X60040400.bin 0x60040400
  2. loadAddress=60040400
  3. The new boot image has been generated!

  4. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>sleep 20

  5. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>blhost.exe -t 50000 -u 0x15a2,0x0073 -j -- get-property 1 0
  6. {
  7.    "command" : "get-property",
  8.    "response" : [ 1258424320 ],
  9.    "status" : {
  10.       "description" : "0 (0x0) Success.",
  11.       "value" : 0
  12.    }
  13. }

  14. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>sleep 20

  15. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>blhost.exe -u -t 1000000 -- flash-erase-region 0x6003c000 0x4000
  16. Inject command 'flash-erase-region'
  17. Successful generic response to command 'flash-erase-region'
  18. Response status = 0 (0x0) Success.

  19. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>sleep 50

  20. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>blhost -u -t 5000 -- flash-erase-region 0x60040000 0x10000
  21. Inject command 'flash-erase-region'
  22. Successful generic response to command 'flash-erase-region'
  23. Response status = 0 (0x0) Success.

  24. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>sleep 50

  25. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>blhost -u -t 5000 -- write-memory 0x60040000 boot_img_crc32.bin
  26. Inject command 'write-memory'
  27. Preparing to send 21516 (0x540c) bytes to the target.
  28. Successful generic response to command 'write-memory'
  29. (1/1)100% Completed!
  30. Successful generic response to command 'write-memory'
  31. Response status = 0 (0x0) Success.
  32. Wrote 21516 of 21516 bytes.

  33. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>sleep 100

  34. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>image_header_padding.exe evkmimxrt1060_APP2_0X60240400.bin 0x60040400
  35. loadAddress=60040400
  36. The new boot image has been generated!

  37. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>sleep 20

  38. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>blhost -u -t 5000 -- flash-erase-region 0x60240000 0x10000
  39. Inject command 'flash-erase-region'
  40. Successful generic response to command 'flash-erase-region'
  41. Response status = 0 (0x0) Success.

  42. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>sleep 50

  43. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>blhost -u -t 5000 -- flash-erase-region 0x6043b000 0x10000
  44. Inject command 'flash-erase-region'
  45. Successful generic response to command 'flash-erase-region'
  46. Response status = 0 (0x0) Success.

  47. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>sleep 50

  48. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>blhost -u -t 5000 -- write-memory 0x60240000 boot_img_crc32.bin
  49. Inject command 'write-memory'
  50. Preparing to send 21516 (0x540c) bytes to the target.
  51. Successful generic response to command 'write-memory'
  52. (1/1)100% Completed!
  53. Successful generic response to command 'write-memory'
  54. Response status = 0 (0x0) Success.
  55. Wrote 21516 of 21516 bytes.

  56. C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>sleep 100
复制代码


evkmimxrt1060_APP1_0X60040000.zip (663.21 KB, 下载次数: 43)
回复

使用道具 举报

  • TA的每日心情
    奋斗
    2023-2-24 18:42
  • 签到天数: 206 天

    连续签到: 1 天

    [LV.7]常住居民III

    19

    主题

    316

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    2792
    最后登录
    2025-3-19
    发表于 2021-7-19 19:33:34 | 显示全部楼层
    本帖最后由 l3142600073 于 2021-7-20 13:37 编辑

    牛x!学习学习
    哎...今天够累的,签到来了~
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2025-7-11 08:53
  • 签到天数: 301 天

    连续签到: 2 天

    [LV.8]以坛为家I

    3916

    主题

    7534

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    39873
    最后登录
    2025-8-15
    发表于 2021-7-20 11:06:21 | 显示全部楼层

    这、、、、、
    qiandao qiandao
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2021-4-15 14:49
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    19

    主题

    132

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    1237
    最后登录
    2025-7-11
    发表于 2021-7-20 11:30:36 | 显示全部楼层
    写得真详细,不错。
    不过这里还是有一个问题。
    App1,App2最好是不要规定地址。开发完成后,发给用户不知道那个版本是那个地址。
    如何解决这个问题?拷贝到SDRAM运行??
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    715

    主题

    6374

    帖子

    0

    超级版主

    Rank: 8Rank: 8

    积分
    25182
    最后登录
    2025-8-12
     楼主| 发表于 2021-7-20 13:42:12 | 显示全部楼层
    waterkingchen 发表于 2021-7-20 11:30
    写得真详细,不错。
    不过这里还是有一个问题。
    App1,App2最好是不要规定地址。开发完成后,发给用户不知道 ...

                    if (bl_get_update_partition_info(&update_partition) != kStatus_Success)
                    {
                        /* Could not get update partition info */
                        PRINTF("Could not get update partition info\r\n");
                        response.status_code = HTTPSRV_CODE_INTERNAL_ERROR;
                    }
                    else if ((stored = store_update_image(mpr_ctx, update_partition.start, update_partition.size)) <= 0)
                    {
                        /* Error during upload */
                        PRINTF("Error during upload\r\n");
                        response.status_code = HTTPSRV_CODE_INTERNAL_ERROR;
                    }
    通过get_update_partition_info 获取partition的信息,从而指定需要更新的image的写入地址
    对于你自己的APP,你正常生成bin文件即可。
    具体你可以参考下lwip_httypssrv_ota_enet这个代码,里面有自生直接更新代码的例子,APP带有写flash的功能。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2021-4-15 14:49
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    19

    主题

    132

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    1237
    最后登录
    2025-7-11
    发表于 2021-7-20 13:55:08 | 显示全部楼层
    小恩GG 发表于 2021-7-20 13:42
    if (bl_get_update_partition_info(&update_partition) != kStatus_Success)
               ...

    这样就完美。
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    0

    主题

    2

    帖子

    0

    新手上路

    Rank: 1

    积分
    43
    最后登录
    2022-6-8
    发表于 2021-8-27 08:04:54 | 显示全部楼层
    有没有研究IAP更新APP呢,我写了一个,下载到板子,死机,查了好久,还是没找到问题所在
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    715

    主题

    6374

    帖子

    0

    超级版主

    Rank: 8Rank: 8

    积分
    25182
    最后登录
    2025-8-12
     楼主| 发表于 2021-8-31 12:18:55 | 显示全部楼层
    茗轩孤月 发表于 2021-8-27 08:04
    有没有研究IAP更新APP呢,我写了一个,下载到板子,死机,查了好久,还是没找到问题所在 ...

    下载到板子死机,首先你要确认你的APP是能够准确跑起来的,比如,如果你直接把你的APP下载到目标地址,可以使用MCUbootUtility下载进对应flash地址,你是否能够成功boot起来?
    如果能够成功boot,那么你就要查看你死机的情况下,读出来你的APP是否下载完整了?是否还有残缺,这样就可以定位到你的IAP下载代码了。
    所以,还是需要先做一个问题定位,然后进一步查看出错点。
    如果还有问题,欢迎发问题贴交流。
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    2

    主题

    6

    帖子

    0

    注册会员

    Rank: 2

    积分
    93
    最后登录
    2024-9-5
    发表于 2023-8-29 17:04:37 | 显示全部楼层
    本帖最后由 eefocus_3892993 于 2023-8-29 17:28 编辑

    大佬有个问题请教一下,就是APP2交换过去以后,他的加载、运行地址和APP1所在地址并不匹配,APP2交换过去以后为什么可以运行呢?
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2021-5-28 05:36
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    2

    主题

    36

    帖子

    0

    注册会员

    Rank: 2

    积分
    153
    最后登录
    2025-5-20
    发表于 2024-2-21 17:20:59 | 显示全部楼层
    eefocus_3892993 发表于 2023-8-29 17:04
    大佬有个问题请教一下,就是APP2交换过去以后,他的加载、运行地址和APP1所在地址并不匹配,APP2交换过去以 ...

    看这个0x400AC078就知道了
    干不完的事
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-8-17 02:14 , Processed in 0.115654 second(s), 29 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

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