本学期的第一次嵌入式(小)作业,出现了许多问题和解决办法,特开一文用以记录,以防忘记。
(1)code32
表示后面全部用 ARM 指令集!
(2)点击 debug,若出现如下错误:error starting external process process error code 87(0x57) can’t read symbolics for this tar
,请以管理员身份重新运行 ADS。
(3)编译时,若AREA
出现unknown opcode
,解决办法:AREA
前面要加空格,不要顶格写,否则编译不通过!另外程序文件最开始最好空一行出来。
(4)在写 C 语言内嵌 ARM 汇编的程序时,主函数的名字不是main
而要写成xmain
或_main
,否则编译不通过!
(5)编译时出现Warning: L6305W: Image does not have an entry point.(Not specified or not set due to multiple choices.)
的警告,我不太了解这个是怎样解决的。
之前也自学过 x86 汇编,但从未写过一个完整的汇编程序。这次作业使用 ARM 汇编写程序,虽然与 x86 语法有较大的区别,但还是很容易理解的。
注意,如果使用LDR
指令来读取数据段的字符串内容,会将整个字符串都读到寄存器中,不便于分离单个字符进行计数。因为LDR
指令会加载整个字放入寄存器中。
而现在我们需要将一字节内容放入到寄存器中,通过查阅指令集,可以发现LDRB
和LDRSB
可以达到这个目的,有所区别的是后者为带符号字节读入。
按理说应该两个指令都可以,但我试了一下,只有LDRSB
可以,用LDRB
还是会整个字读入,不知道是什么原因,希望有知情者可以解释一下。
AREA COPY, CODE, READONLY
ENTRY
CODE32
START
LDR R5, =RESULT
LDR R0, =DATA
MOV R1, #0 ;统计数字次数
MOV R2, #20 ;循环次数
MOV R3, #0 ;测试是否为数字,若是则为负数
B LOOP
NUMBER
ADD R1, R1, #1 ;数字字符,加一
B NEXT
LOOP
LDRSB R4, [R0] ;从源地址获取数据
;数字字符ASCII:48-57
CMP R4, #47
BLE NEXT
CMP R4, #58
BLE NUMBER
NEXT
ADD R0, R0, #1 ;地址
SUB R2, R2, #1 ;循环减一
CMP R2, #0
BNE LOOP
STR R1, [R5]
B EXIT
EXIT
B EXIT
AREA COPYDATA, DATA, READONLY
DATA DCB "012abc34def56dd78j90"
RESULT DCD 0
END
调试过程中:
n 个人围成一圈,编号从 1 到 n ,从编号为 1 的人开始报数,报到 m 的人离队,下面的人接着从1开始报数,依次下去,写程序求最后剩下一个人编号是几?
有点惭愧,因为当时时间紧迫,这个题目我是直接拿网上的用 x86 汇编写的程序改的(前往:用80x86汇编 求约瑟夫环问题)。数据段分为两个部分,FLAG
段是标记出列,RESULT
记录出列标号。
这里给出的是 10 个人围成一圈,报到 4 时出列的约瑟夫问题求解程序。
AREA COPY, CODE, READONLY
ENTRY
START
LDR R8, =RESULT
LDR R6, =FLAG
MOV R0, #10 ;总共10个人
MOV R1, #4 ;出列号码4
MOV R2, #0 ;起始号码
MOV R3, #0 ;报数
MOV R4, #0 ;出列人数
MOV R5, #0 ;用于保存出列号码
L1
LDR R7, [R6, R2, LSL #2] ;R7=地址(R6+R2*4)的值
CMP R7, #0 ;检测是否为出列
BNE NEXT ;若不是,则转到下一个人处理
ADD R3, R3, #1 ;若是,则报数,加一
CMP R3, R1 ;检测是否已经报到出列号码
BNE NEXT ;若不是,则转到下一个人处理
ADD R7, R7, #1 ;若是,则标记出列
STR R7, [R6, R2, LSL #2] ;记录回memory
MOV R3, #0 ;报数重新置零
MOV R5, R2 ;保存出列号码
STR R5, [R8, R4, LSL #2]
ADD R4, R4, #1 ;出列人数加一
CMP R4, R0 ;检测出列人数是否等于总人数
BEQ EXIT ;若是,则结束程序
NEXT
ADD R2, R2, #1 ;转到下一个人
CMP R2, R0 ;检测是否数到了最后一个人
BNE L1 ;若不是,则继续数
MOV R2, #0 ;若是,起始号码从0开始数
B L1
EXIT
B EXIT
AREA COPYDATA, DATA, READWRITE
FLAG DCD 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
RESULT DCD 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
END
将上面汇编程序改成 C 语言和 ARM 汇编混合。注意,LDR R8, [result]
若写为LDR R8, =result
编译时就会报错,不知道为什么。
我调试过,一直出现找不到函数入口,PC 指针一直指向初始位置,因此也无法得知该程序是否正确与否。在Edit->DebugRel Settings
里设置Image entry point
也没用,希望能有朝一日能解决这个问题。
#include
#include
int _main()
{
int num[100];
int n=10, m=4, i;
int count, locate, sum;
int result[100];
for(i = 0; i < n; i++)
num[i] = 0;
__asm
{
LDR R8, [result]
LDR R6, [num]
LDR R0, [n]
LDR R1, [m]
LDR R2, [locate]
LDR R3, [count]
LDR R4, [sum]
LOOP:
LDR R7, [R6, R2]
CMP R7, #0
BNE NEXT
ADD R3, R3, #1
CMP R3, R1
BNE NEXT
ADD R7, R7, #1
MOV R3, #0
ADD R4, R4, #1
ADD R8, R8, R4
STR R2, [R8]
CMP R4, R0
NEXT:
ADD R2, R2, #1
CMP R2, R0
BNE LOOP
MOV R2, #0
B LOOP
}
for(i = 0; i < n; i++)
printf("%d ", result[i]);
return 0;
}