首页 > 解决方案 > 将变量从 C 代码传递到汇编并返回的正确语法是什么?

问题描述

苦苦挣扎的电气工程专业学生试图将 C 语言和汇编语言 (ARM32 Cortex-M) 联系起来,以完成嵌入式系统的最终项目。我不完全理解这个项目的正确语法。

我被指示结合之前的 2 个实验 - 以及额外的代码 - 在 MBED 环境中使用 C 和汇编语言构建一个简单的计算器(+、-、*、/)。我已将 C 文件设置为扫描键盘,将 3 个用户输入输入到 3 个字符串,然后将这些字符串传递给程序集文件。汇编文件用于执行算术函数并将结果保存在 EXPORT PROC 中。然后我的 C 文件将结果和 printf 提供给用户(我们使用 PuTTY 读取)。

这是我的程序集标题和导入链接:

    AREA calculator, CODE, READONLY ; assembly header

compute_asm
          IMPORT OPERAND_1 ; imports from C file
          IMPORT OPERAND_2 ; imports from C file
          IMPORT USER_OPERATION ; imports from C file
          ALIGN ; aligns memory

initial_values PROC 
          LDR R1, =OPERAND_1; loads R1 with OPERAND_1
          LDR R2, =OPERAND_2; loads R2 with OPERAND_2 

以下是我的 C 文件中链接到程序集的几行:

int OPERAND_1; //declares OPERAND_1 for Assembly use
int OPERAND_2; //declares OPERAND_2 for Assembly use
int USER_OPERATION; //declares USER_OPERATION for Assembly use

extern int add_number(); //links add_number function in Assembly
extern int subtract_number(); //links subtract_number function in Assembly

我希望能够编译和使用这段代码(之前的实验比这个项目顺利得多)。但是在解决了一些其他语法问题之后,我在编译时收到“错误:“/tmp/fOofpw”,第 39 行:警告:#47-D:宏“MBED_RAM_SIZE”的不兼容重新定义。

编码是我的弱点。任何帮助或指示将不胜感激!

标签: cassemblyarmmbed

解决方案


通常,特定目标的特定编译器版本使用的调用约定特定于该编译器和版本。并且技术上随时可能发生变化(即使我们已经看到了 gnu 和 arm),并且没有理由期望任何其他编译器符合相同的约定。尽管像 gcc 和 clang 这样的编译器符合 arm 推荐的 abi 的某个版本,但随着时间的推移,abi 已经发生了变化,而 gcc 也随之发生了变化。

As Peter pointed out:

LDR R1, =OPERAND_1; loads R1 with OPERAND_1

(you are clearly not using gnu assembler, so not the gnu toolchain correct? probably Kiel or ARM?)

puts the address of that label into r1 to get the contents you need another load

ldr r1,[r1]

and now the contents are there.

Using global variables gets you around the calling convention problem.

Using a simple example and disassembling you can discover the calling convention for your compiler:

extern unsigned int add ( unsigned int, unsigned int);
unsigned int fun ( void )
{
    return(add(3,4)+2);
}
00000000 <fun>:
   0:   b510        push    {r4, lr}
   2:   2104        movs    r1, #4
   4:   2003        movs    r0, #3
   6:   f7ff fffe   bl  0 <add>
   a:   3002        adds    r0, #2
   c:   bd10        pop {r4, pc}
   e:   46c0        nop         ; (mov r8, r8)

first parameter in r0, second in r1, return in r0. which could technically change on any version of gnu going forward but can tell you from gcc 2.x.x to the present 9.1.0 this is how it has been for arm. gcc 3.x.x to the present for thumb which is what you are using.

How you have done it is fine, you just need to recognize what the =LABEL shortcut thing really does.


推荐阅读