This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] SK-AM62B-P1:使用 MCU+ SDK 时链接器错误

Guru**** 2482225 points
Other Parts Discussed in Thread: SYSCONFIG

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1423003/sk-am62b-p1-linker-error-while-using-mcu-sdk

器件型号:SK-AM62B-P1
主题中讨论的其他器件:SysConfig

工具与软件:

我在构建启用了 IPC,I2C,GPIO 和 SPI 的二进制文件时遇到此错误:

[  297.873902] remoteproc remoteproc0: powering up 5000000.m4fss
[  297.889147] remoteproc remoteproc0: Booting fw image am62-mcu-m4f0_0-fw, size 71480
[  297.901798] remoteproc remoteproc0: bad phdr da 0x30000 mem 0x11f80
[  297.913478] remoteproc remoteproc0: Failed to load program segments: -22
[  297.920853] remoteproc remoteproc0: Boot failed: -22
-sh: echo: write error: Invalid argument

就我而言、这表示加载固件映像时发生了错误。 phdr指程序标头、它是描述存储器中固件映像布局的数据结构。 该错误消息提示da 0x30000mem 0x11f80程序标头的预期内存地址()与实际内存地址()不匹配。 以下是我已修改的 linker.cmd 文件(堆和 M4F DRAM 的长度):

/* make sure below retain is there in your linker command file, it keeps the vector table in the final binary */
--retain="*(.vectors)"
/* This is the stack that is used by code running within main()`
 * In case of NORTOS,
 * - This means all the code outside of ISR uses this stack
 * In case of FreeRTOS
 * - This means all the code until vTaskStartScheduler() is called in main()
 *   uses this stack.
 * - After vTaskStartScheduler() each task created in FreeRTOS has its own stack
 */
--stack_size=16384
/* This is the heap size for malloc() API in NORTOS and FreeRTOS
 * This is also the heap used by pvPortMalloc in FreeRTOS
 */
--heap_size=65536 


SECTIONS
{
    /* This has the M4F entry point and vector table, this MUST be at 0x0 */
    .vectors:{} palign(8) > M4F_VECS
    .text:   {} palign(8) > M4F_IRAM     /* This is where code resides */

    .bss:    {} palign(8) > M4F_DRAM     /* This is where uninitialized globals go */
    RUN_START(__BSS_START) 
    RUN_END(__BSS_END)

    .data:   {} palign(8) > M4F_DRAM     /* This is where initialized globals and static go */
    .rodata: {} palign(8) > M4F_DRAM     /* This is where const's go */
    .sysmem: {} palign(8) > M4F_IRAM     /* This is where the malloc heap goes */
    .stack:  {} palign(8) > M4F_IRAM     /* This is where the main() stack goes */

    GROUP {
        /* This is the resource table used by linux to know where the IPC "VRINGs" are located */
        .resource_table: {} palign(4096)
    } > DDR_IPC_RESOURCE_TABLE_LINUX

    /* Sections needed for C++ projects */
    .ARM.exidx:     {} palign(8) > M4F_IRAM  /* Needed for C++ exception handling */
    .init_array:    {} palign(8) > M4F_IRAM  /* Contains function pointers called before main */
    .fini_array:    {} palign(8) > M4F_IRAM  /* Contains function pointers called after main */
    /* this is used only when IPC RPMessage is enabled, else this is not used */
    .bss.ipc_vring_mem   (NOLOAD) : {} > DDR_IPC_VRING_RTOS
}

MEMORY
{
    M4F_VECS : ORIGIN = 0x00000000 , LENGTH = 0x00000200
    M4F_IRAM : ORIGIN = 0x00000200 , LENGTH = 0x0002FE00
    M4F_DRAM : ORIGIN = 0x00030000 , LENGTH = 0x00015000

    /* when using multi-core application's i.e more than one R5F/M4F active, make sure
     * this memory does not overlap with R5F's
     */
    /* Resource table must be placed at the start of DDR_IPC_RESOURCE_TABLE_LINUX when M4 core is early booting with Linux */
    DDR_IPC_RESOURCE_TABLE_LINUX       : ORIGIN = 0x9CC00000 , LENGTH = 0x1000


    DDR_IPC_VRING_RTOS: ORIGIN = 0x9C800000, LENGTH = 0x00300000
}



这是 main.c 文件:

#include <stdlib.h>
#include <kernel/dpl/DebugP.h>
#include "ti_drivers_config.h"
#include "ti_board_config.h"
#include "ti_drivers_open_close.h"
#include "ti_board_open_close.h"
#include "FreeRTOS.h"
#include "task.h"

#define MAIN_TASK_PRI  (configMAX_PRIORITIES-1)
#define MAIN_TASK_SIZE (16384U/sizeof(configSTACK_DEPTH_TYPE))
#define I2C_TASK_PRI (configMAX_PRIORITIES-2)
#define I2C_TASK_SIZE (4096U/sizeof(configSTACK_DEPTH_TYPE))
#define GPIO_TASK_PRI (configMAX_PRIORITIES-3)
#define GPIO_TASK_SIZE (1024U/sizeof(configSTACK_DEPTH_TYPE))

StackType_t gMainTaskStack[MAIN_TASK_SIZE] __attribute__((aligned(32)));
StaticTask_t gMainTaskObj;
TaskHandle_t gMainTask;

StackType_t gI2CTaskStack[I2C_TASK_SIZE] __attribute__((aligned(32)));
StaticTask_t gI2CTaskObj;
TaskHandle_t gI2CTask;

StackType_t gGPIOTaskStack[GPIO_TASK_SIZE] __attribute__((aligned(32)));
StaticTask_t gGPIOTaskObj;
TaskHandle_t gGPIOTask;

void empty_main_i2c(void *arg0);
void gpio_led_blink_main(void *args);
void *empty_main_spi(void *arg0);


StackType_t gMainTaskStack1[MAIN_TASK_SIZE] __attribute__((aligned(32)));

StaticTask_t gMainTaskObj1;
TaskHandle_t gMainTask1;

void empty_main(void *args);


void empty_main1(void *args){

    int32_t status = SystemP_SUCCESS;

    /* Open drivers */
    Drivers_open();
    /* Open flash and board drivers */
    status = Board_driversOpen();
    DebugP_assert(status==SystemP_SUCCESS);

    empty_main(NULL);

    /* Close board and flash drivers */
    Board_driversClose();
    /* Close drivers */
    Drivers_close();

    vTaskDelete(NULL);

}

void freertos_main(void *args)
{
    int32_t status = SystemP_SUCCESS;

    /* Open drivers */
    Drivers_open();
    /* Open flash and board drivers */
    status = Board_driversOpen();
    DebugP_assert(status == SystemP_SUCCESS);

    /* Create the hello world task */
    gI2CTask = xTaskCreateStatic(empty_main_i2c,    /* Pointer to the task function */
                                   "empty_main_i2c",  /* Task name for debugging */
                                   I2C_TASK_SIZE,     /* Stack size */
                                   NULL,                /* Task parameter */
                                   I2C_TASK_PRI,      /* Task priority */
                                   gI2CTaskStack,     /* Stack buffer */
                                   &gI2CTaskObj);     /* Task control block */
    configASSERT(gI2CTask != NULL);

    /* Create the beautiful task */
    gGPIOTask = xTaskCreateStatic(gpio_led_blink_main,    /* Pointer to the task function */
                                       "gpio_led_blink_main",  /* Task name for debugging */
                                       GPIO_TASK_SIZE,/* Stack size */
                                       NULL,              /* Task parameter */
                                       GPIO_TASK_PRI, /* Task priority */
                                       gGPIOTaskStack,/* Stack buffer */
                                       &gGPIOTaskObj);/* Task control block */
    configASSERT(gGPIOTask != NULL);

    empty_main_spi(NULL);

    /* Close board and flash drivers */
    Board_driversClose();
    /* Close drivers */
    Drivers_close();

    vTaskDelete(NULL);
}

int main()
{
    /* init SOC specific modules */
    System_init();
    Board_init();

    /* This task is created at highest priority, it should create more tasks and then delete itself */
    gMainTask = xTaskCreateStatic(freertos_main,   /* Pointer to the function that implements the task. */
                                  "freertos_main", /* Task name for debugging */
                                  MAIN_TASK_SIZE,  /* Stack size */
                                  NULL,            /* Task parameter */
                                  MAIN_TASK_PRI,   /* Task priority */
                                  gMainTaskStack,  /* Stack buffer */
                                  &gMainTaskObj);  /* Task control block */
    configASSERT(gMainTask != NULL);



	
	
     gMainTask = xTaskCreateStatic(empty_main1,   /* Pointer to the function that implements the task. */
                                  "empty_main", /* Task name for debugging */
                                  MAIN_TASK_SIZE,  /* Stack size */
                                  NULL,            /* Task parameter */
                                  MAIN_TASK_PRI,   /* Task priority */
                                  gMainTaskStack1,  /* Stack buffer */
                                  &gMainTaskObj1);  /* Task control block */
    configASSERT(gMainTask != NULL);
    /* Start the scheduler to start the tasks executing. */
    vTaskStartScheduler();

    /* This line should never be reached */
    DebugP_assertNoLog(0);

    return 0;
}


我到底在哪里做错了?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    大家好、我今天不在办公室。 我会在一周结束时回到你身边。 如果您在星期五之前尚未获得答案、请随时向我 ping 通

    谢谢!

    Paula.  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    大家好、Chris、我来问您几个问题。

    -您是否能够遵循和运行学院的 IPC 示例?

    处理器间通信(IPC)

    MCU+到 MCU+ IPC 示例入门

    -同时,当您在 linker.cmd 中修改 M4f_DRAM 大小时,是否可以反转更改? 以查看是不是这是导致问题的原因。

    谢谢!

    Paula.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Paula:
    是的,可以反转更改,但同时它不编译并给出错误,这一个:

    "linker.cmd", line 25: error: program will not fit into available memory, or
       the section contains a call site that requires a trampoline that can't be
       generated for this section. run placement with alignment fails for section
       ".bss" size 0x11f3a.  Available memory ranges:
       M4F_DRAM     size: 0x10000      unused: 0xd608       max hole: 0xd608    
    error: errors encountered during linking; "empty.release.out" not built
    tiarmclang: error: tiarmlnk command failed with exit code 1 (use -v to see invocation)
    
    



    我在 linker.cmd 中更改 M4f_dram 的大小后、它会被编译、但不会在 EVM 中运行、它会给出我在问题中发布的错误。 "你以为我赢了吗?
    此致、
    Shreyan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Jain、如果您增加了 M4F_DRAM、则需要减小 M4F_IRAM。 M4F TCM 为256KB。 一个选项是将.bss 段从 M4F_DRAM 移动到 DDR

    以下为类似主题: (+) PROCESSOR-SDK-AM62X:"linker.cmd"、第 xx 行:错误:程序无法放入可用存储器中-处理器论坛-处理器- TI E2E 支持论坛

    谢谢!

    Paula.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Paula:

    一个选项是将.bss 段从 M4F_DRAM 移动到 DDR

    我做了这些改变,但它不工作,请让我知道我需要做什么


    /* make sure below retain is there in your linker command file, it keeps the vector table in the final binary */
    --retain="*(.vectors)"
    /* This is the stack that is used by code running within main()
     * In case of NORTOS,
     * - This means all the code outside of ISR uses this stack
     * In case of FreeRTOS
     * - This means all the code until vTaskStartScheduler() is called in main()
     *   uses this stack.
     * - After vTaskStartScheduler() each task created in FreeRTOS has its own stack
     */
    --stack_size=32768
    /* This is the heap size for malloc() API in NORTOS and FreeRTOS
     * This is also the heap used by pvPortMalloc in FreeRTOS
     */
    --heap_size=65536
    
    SECTIONS
    {
        /* This has the M4F entry point and vector table, this MUST be at 0x0 */
        .vectors:{} palign(8) > M4F_VECS
        .text:   {} palign(8) > M4F_IRAM     /* This is where code resides */
    
        /* Move .bss section to DDR_IPC_VRING_RTOS */
        .bss:    {} palign(8) > DDR_IPC_VRING_RTOS     /* This is where uninitialized globals go */
        RUN_START(__BSS_START)
        RUN_END(__BSS_END)
    
        .data:   {} palign(8) > M4F_DRAM     /* This is where initialized globals and static go */
        .rodata: {} palign(8) > M4F_DRAM     /* This is where const's go */
        .sysmem: {} palign(8) > M4F_IRAM     /* This is where the malloc heap goes */
        .stack:  {} palign(8) > M4F_IRAM     /* This is where the main() stack goes */
    
        GROUP {
            /* This is the resource table used by linux to know where the IPC "VRINGs" are located */
            .resource_table: {} palign(4096)
        } > DDR_IPC_RESOURCE_TABLE_LINUX
    
        /* Sections needed for C++ projects */
        .ARM.exidx:     {} palign(8) > M4F_IRAM  /* Needed for C++ exception handling */
        .init_array:    {} palign(8) > M4F_IRAM  /* Contains function pointers called before main */
        .fini_array:    {} palign(8) > M4F_IRAM  /* Contains function pointers called after main */
        .bss.ipc_vring_mem   (NOLOAD) : {} > DDR_IPC_VRING_RTOS
    }
    
    MEMORY
    {
        M4F_VECS : ORIGIN = 0x00000000 , LENGTH = 0x00000200
        M4F_IRAM : ORIGIN = 0x00000200 , LENGTH = 0x0002FE00  /* Decrease this size */
        M4F_DRAM : ORIGIN = 0x00030000 , LENGTH = 0x00040000  /* Increase this size */
    
        DDR_IPC_RESOURCE_TABLE_LINUX       : ORIGIN = 0x9CC00000 , LENGTH = 0x1000
    
        DDR_IPC_VRING_RTOS: ORIGIN = 0x9C800000, LENGTH = 0x00300000
    }
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Jain、您好、请创建另一个 DDR 存储器区域。 您可以从 SysConfig (+Add)执行此操作。 请注意其他内核和 IPC 已经在使用 DDR 中的哪些区域

    然后您可以将段(在本例中为.bss)移动到新创建的 DDR 存储器区域

    如果不使用 SysConfig、也可以通过链接器命令执行此操作。  

    有关 IPC 的更多信息、我建议查看 AM62x IPC 学院: 处理器间通信(IPC)

    我找到了此常见问题解答、不是直接针对您的用例、但该常见问题解答对多核示例的存储器  段和链接器命令脚本进行了很好的解释、并且他们在其中为不同的段放置添加了两个 DDR 存储器区域。 此外、还添加了代码供您查看。

    (+)[常见问题解答] SK-AM62:如何使用 M4F 内核从外部存储器执行代码? -处理器论坛-处理器- TI E2E 支持论坛

    希望这对您有所帮助、谢谢。

    Paula.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Paula:

    您到底是如何在 SysConfig 中启用存储器区域的? 我得到了这样的消息:



    此致、

    Shreyan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Shreyan、很抱歉、AM62x M4F SysConfig 中没有 DDR。 请尝试修改 linker.cmd (与上面的 FAQ 中的做法类似)、并让我知道它的运作方式。

    谢谢!

    Paula.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Paula:

    我看到过、它显示了相同的错误

    此致、

    Shreyan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Shreyan、您好、"程序不能放入可用内存"的错误含义相同? 还是另一个? 您可以连接它吗? 此外、如果您可以共享项目、也会很有帮助。

    谢谢!

    Paula.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Paula:

    我想我为什么无法做到这一点、这是由于 SysConfig 设置。 如果我尝试按照指示操作、它会给出错误、表明它与某些内容重叠或其他内容。
    此致、

    Shreyan

    我要使用的 MCU SDK 是9.02.01

    e2e.ti.com/.../8204.empty.zip

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Jain、您好、我有点困惑您将什么用作基准示例。 我相信你在尝试 RPmsg,这是正确的吗?

    如果是、您能否构建并运行 C:\ti\mcu_plus_sdk_am62x_09_02_00_38\examples\drivers\ipc\ipc_rpmsg_echo_linux?
    远程内核上的应用开发

    如果您再举一个例子、请告诉我。 我想尝试重现该问题、但从"已知良好"的起点(项目)开始

    谢谢!

    Paula.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Paula:

    是的、我尝试执行 RPmsg、但同时我也尝试在代码中包含 IPC、SPI 和 GPIO、以与这些引脚和 I/O 扩展器进行交互。 我已经将 MCU SDK 中的"empy"示例作为起点

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    好的、Jain、但 RPmsg 演示运行正常。 对吗?  

    您正在运行以下哪两项?

    AM62x MCU+ SDK: IPC RP 消息回显

    AM62x MCU+ SDK: IPC RP 消息 Linux 回显

    谢谢!

    Paula.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    亲爱的 Paula

    RPMSG Linux Echo 起作用、但我在 SysConfig 中启用 IPC、它会提供我提到的错误。

    此致、

    Shreyan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Jain、获得了、请确认您正在使用两个 RPmsg Echo 演示(上面的消息)中的哪一个。 我想尝试重现该问题。

    谢谢你

    Paula.  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Paula,

    AM62x MCU+ SDK: IPC RP 消息 Linux 回显

    这个

    此致、

    Shreyan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好 Shreyan ,对不起我迟到的答复。 我不得不在过去的两周里休息几天。  
    例如、我在(ipc_rpmsg_echo_linux_am62x-sk_m4fss0-0_freertos_ti-arm-clang)上创建了一个工程。

    我在顶部的 IPC RPMSG 回显演示中所做的是:

    -添加 GPIO LED 闪烁(gpio_led_blink_am62x-sk_m4fss0-0_freertos_ti-arm-clang)

    -添加 I2C LED 闪烁(i2c_led_blink_am62x-sk_m4fss0-0_freertos_ti-arm-clang)

    -添加 MCSPI (mcspi_loopback_am62x-sk_m4fss0-0_freertos_ti-arm-clang)

    -添加一个具有简单 memcpy 测试的 DDR buf (这是在 i2c_led_blink.c 内部添加的)

    从 UART 日志中、我看到所有演示都运行正常。 当然、最终的应用会更复杂、但至少这可以作为基准。

    在 SysConfig 中、我为 0x9CB00000添加了一个 MPU 区域(我放置缓冲器的 DDR 部分)。 在链接器命令中、我在存储器中以及组内的下方添加了 DDR_1

    组:{
    .ddr_buf:{
    }对齐(8)
    }> DDR_1

    然后在"i2c_led_blink.c"内部使用"ddr_buf"进行复制、并从中进行复制。

    移动部分有点棘手。 我遇到了你原来的错误"bad phdr da"和"没能加载程序段:-22"几次。 所以、需要特别小心。

    随附的示例项目。 如果您有任何其他问题、请告诉我这是否可行

    e2e.ti.com/.../5327.ipc_5F00_rpmsg_5F00_echo_5F00_linux_5F00_am62x_2D00_sk_5F00_m4fss0_2D00_0_5F00_freertos_5F00_ti_2D00_arm_2D00_clang.zip

    谢谢你

    Paula.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Paula:

    不会、会产生相同的误差。 我已将我正在使用的文件夹附加到附件中、请告诉我、我是否在结束时有任何错误、或者我是否应该做任何事情。

    e2e.ti.com/.../5148.empty.zip

    此致、

    Shreyan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Shreyan、您能给我发送说明我应该使用哪些项目吗? 换言之、我应基于如何运行该软件来构建该软件、从而快速重现问题。

    另一方面、我的项目是否为您构建和运行正常?

    谢谢!

    Paula.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Paula:

    我不会介意的,我会尝试重复你做的,并读的文档,并回到你。

    感谢您的帮助、感谢您的帮助。

    此致、

    Shreyan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Paula:

    想要在移动存储器上投入一些光吗?

    此致、

    Shreyan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好、Jain、很抱歉我的回复太晚了。 我是 OOO。 如果您仍有问题或问题已得到解决、请告诉我

    谢谢!

    Paula.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Paula:

    对于存储器区域的移动、您会建议什么参考材料?

    非常感谢

    此致

    Shreyan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好、Jain、如果你没有、我建议你去看看学院

    如何分配存储器

    如果这有助于或者您有任何具体问题、请告诉我们

    谢谢!

    Paula.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Paula:

    好的、谢谢

    此致、

    Shreyan