我最近一直在学习汇编程序设计,并且正在尝试为作业编写程序。我有一个在屏幕上画一条线的函数/标签。
问题在于,第一次调用该函数后,第二次没有调用该函数。我正在使用“ bl标签”调用该函数,并使用“ bx lr”返回到入口点。
我使用的编译器是在Raspberry Pi 2上运行的FASM v1.43
负责调用画线的主文件的一部分:
mov r4, #309 ;x
mov r5, #219 ;y
;draw veritcal line
push{r11,r10,r5,r4}
;vertical or horizontal
mov r10,#1
;length
mov r11,$0100
orr r11,$0003
bl drawline
pop{r4,r5,r10,r11}
;draw second vertical line
push{r11,r10,r5,r4}
mov r10,#1
mov r4, #349 ;x
mov r11,$0100
orr r11,$0003
bl drawline
pop{r4,r5,r10,r11}
画图线中的代码被称为:
rect_vloop:
push {r0-r3}
mov r0,r7 ;screen address
mov r1,r4 ;x
mov r2,r5 ;y
mov r3,r6 ;colour
;assume BITS_PER_PIXEL, SCREEN_X are shared constants
bl drawpixel
pop {r0-r3}
;increment and test
add r5,#1
mov r8,r11
cmp r5,r8
bls rect_vloop
dl_end:
bx lr
我没有写drawpixel,我已经知道它可以工作。
第一行像应该绘制到屏幕上一样,但是第二行不绘制,删除第一个调用将进行第二次绘制,所以我想说我搞砸了返回函数,但是我不知道是什么我做错了。
谢谢。
答案 0 :(得分:0)
不是所有的代码都出现在问题中,但是引人注目的主要是您没有在函数内部和函数之间保留正确的寄存器。
ARM Application Binary Interface指定r0-r3
用于传递参数和返回值,因此在函数中保留r0-r3
的值是不正确的。的确,ABI指出
子例程必须保留寄存器
r4-r8
,r10
,r11
和SP
(以及r9
在指定{{1 }}作为r9
)
,如果您不确定平台上v6
的状态,请放心并保存它。
因此,您需要在调用函数之前保留r9
和r0-r3
中的重要内容,并在其中保留r12
。您还需要确保函数的堆栈使用平衡,从而保留r4-r11
(sp
)。
如果您的函数调用任何其他函数,则还必须保留链接寄存器(r13
,lr
),否则您将丢失返回地址(r14
中也缺少此步骤,因为书面)。
当然,如果您曾经调用过的唯一函数是您自己的,而您的函数仅由您自己的代码调用,则可以违反ABI-但我不知道为什么要这么做,并且不知道仍然需要drawline
。
仅供参考,lr
和push
指令中的寄存器顺序(实际上是pop
和STMDB
)无关紧要;指令以描述要保存或加载的寄存器的位域进行编码,并且它们的存储和检索顺序以递增的寄存器编号占据递增的存储器位置为准。如果您尝试以升序以外的任何方式指定寄存器列表,则大多数ARM汇编程序都会警告您,因为他们认为您正在尝试获取某些特定的加载或存储顺序,而这些都是您无法获得的。
最后请注意,您应该养成按入和弹出偶数个寄存器以保持8字节堆栈对齐的习惯-也许您已经知道这一点,因为您在所提供的代码中进行了此操作。这可以帮助您的代码与需要8字节堆栈对齐的现有代码兼容,其中有很多。