在程序集中调用多个 labels/functions 的问题
Issue with calling multiple labels/functions in assembly
最近在学习汇编编程,正在尝试编写一个作业程序。我有一个 function/label 在屏幕上画一条线。
问题是第一次调用函数后,第二次没有调用。我正在使用 'bl label' 调用函数,并使用 'bx lr' 到 return 到入口点。
我使用的编译器是 FASM v1.43,运行 Raspberry Pi 2
主文件中负责调用drawline的部分:
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,00
orr r11,[=11=]03
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,00
orr r11,[=11=]03
bl drawline
pop{r4,r5,r10,r11}
drawline 中被调用的代码:
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,但我已经知道它可以工作。
第一行按应有的方式绘制到屏幕上,但第二行不绘制,删除第一个调用会进行第二个绘制,所以我想说我搞砸了 return 函数但我不知道我做错了什么。
提前致谢。
好吧,问题中并没有出现您的所有代码,但突出的主要问题是您没有在函数内部和函数之间保留正确的寄存器。
ARM Application Binary Interface 指定 r0-r3
用于传递参数和 return 值,因此在您的函数中保留 r0-r3
的值是不正确的。事实上,ABI 指出
A subroutine must preserve the contents of the registers r4-r8
, r10
, r11
and SP
(and r9
in PCS variants that designate r9
as v6
)
如果您不确定 r9
在您平台上的状态,请谨慎行事并保存它。
所以你需要在调用函数之前保留 r0-r3
和 r12
中的任何重要内容,并在其中保留 r4-r11
。您还需要确保函数的堆栈使用是平衡的,因此保留 sp
(r13
).
如果您的函数调用任何其他函数,您还必须保留 link 寄存器(lr
、r14
),否则您会丢失 return 地址(这一步drawline
中也缺少书面内容)。
当然,如果您调用的唯一函数是您自己的函数,并且您的函数仅由您自己的代码调用,那么您可能会违反 ABI——但我不知道您为什么要这样做,而且仍然需要 lr
的保存。
仅供参考,push
和 pop
指令中的寄存器顺序(实际上是 STMDB
和 LDMIA
)无关紧要;这些指令使用描述要保存或加载的寄存器的位域进行编码,并且它们存储和检索的顺序是升序的寄存器编号占据升序的内存位置。如果您尝试以除升序以外的任何方式指定寄存器列表,大多数 ARM 汇编程序都会警告您,因为它们假定您正在尝试获得一些您不会获得的特定加载或存储顺序。
最后请注意,您应该养成压入和弹出偶数个寄存器以保持 8 字节堆栈对齐的习惯 - 也许您已经知道这一点,因为您在提供的代码中这样做了。这有助于您的代码与需要 8 字节堆栈对齐的现有代码兼容,其中有很多。
最近在学习汇编编程,正在尝试编写一个作业程序。我有一个 function/label 在屏幕上画一条线。
问题是第一次调用函数后,第二次没有调用。我正在使用 'bl label' 调用函数,并使用 'bx lr' 到 return 到入口点。
我使用的编译器是 FASM v1.43,运行 Raspberry Pi 2
主文件中负责调用drawline的部分:
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,00
orr r11,[=11=]03
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,00
orr r11,[=11=]03
bl drawline
pop{r4,r5,r10,r11}
drawline 中被调用的代码:
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,但我已经知道它可以工作。
第一行按应有的方式绘制到屏幕上,但第二行不绘制,删除第一个调用会进行第二个绘制,所以我想说我搞砸了 return 函数但我不知道我做错了什么。
提前致谢。
好吧,问题中并没有出现您的所有代码,但突出的主要问题是您没有在函数内部和函数之间保留正确的寄存器。
ARM Application Binary Interface 指定 r0-r3
用于传递参数和 return 值,因此在您的函数中保留 r0-r3
的值是不正确的。事实上,ABI 指出
A subroutine must preserve the contents of the registers
r4-r8
,r10
,r11
andSP
(andr9
in PCS variants that designater9
asv6
)
如果您不确定 r9
在您平台上的状态,请谨慎行事并保存它。
所以你需要在调用函数之前保留 r0-r3
和 r12
中的任何重要内容,并在其中保留 r4-r11
。您还需要确保函数的堆栈使用是平衡的,因此保留 sp
(r13
).
如果您的函数调用任何其他函数,您还必须保留 link 寄存器(lr
、r14
),否则您会丢失 return 地址(这一步drawline
中也缺少书面内容)。
当然,如果您调用的唯一函数是您自己的函数,并且您的函数仅由您自己的代码调用,那么您可能会违反 ABI——但我不知道您为什么要这样做,而且仍然需要 lr
的保存。
仅供参考,push
和 pop
指令中的寄存器顺序(实际上是 STMDB
和 LDMIA
)无关紧要;这些指令使用描述要保存或加载的寄存器的位域进行编码,并且它们存储和检索的顺序是升序的寄存器编号占据升序的内存位置。如果您尝试以除升序以外的任何方式指定寄存器列表,大多数 ARM 汇编程序都会警告您,因为它们假定您正在尝试获得一些您不会获得的特定加载或存储顺序。
最后请注意,您应该养成压入和弹出偶数个寄存器以保持 8 字节堆栈对齐的习惯 - 也许您已经知道这一点,因为您在提供的代码中这样做了。这有助于您的代码与需要 8 字节堆栈对齐的现有代码兼容,其中有很多。