我试图写一个ARM程序,它接受三个数字,并计算判别。它有两个源文件,driver.s & prog3.s。我知道如何找到判别,但如何将A、B、&C值从主函数传递到描述函数中?到目前为止,我已经输入了代码.
MAIN() driver.s
avalue .reg r0
bvalue .req r1
cvalue .req r2
final .req r3
loopcount .req r4
readA:
.ascii “%d”
readB:
.ascii “%d”
readC:
.ascii “%d”
addressReadA: .word readA
addressReadB: .word readB
addressReadC: .word readC
main:
ldr avalue, addressReadA @ load in avalue
ldr bvalue, addressReadB @ load in bvalue
ldr cvalue, addressReadC @ load in cvalueDISCRIM()方案3.s
avalue .reg r0
bvalue .req r1
cvalue .req r2
final .req r3
discrim:
mul bvalue, bvalue, bvalue @ square bvalue
mul avalue, avalue, #4 @ multiply avalue by 4
mul cvalue, avalue, cvalue @ multiply avalue by cvalue
add final, bvalue, cvalue @ calculated discriminant 发布于 2016-03-12 16:56:55
遵循C编译器使用的调用约定并不是个坏主意,尤其是如果您从纯汇编程序转到C和asm混合程序,您已经有了这种经验。并且/或您可能会在所使用的调用约定中看到简单和智慧。
您如何知道编译器的调用约定是什么? 1)阅读手册/文档和google。2)试试看。Prototype一个函数,它类似于操作数、操作数的类型和返回值,并给它提供真实的数字,并查看它产生了什么。
编译到asm有时是有效的,但是使用伪指令和汇编程序所做的其他事情,我更喜欢集成而不是编译到asm。
unsigned int fun ( unsigned int a, unsigned int b, unsigned int c );
unsigned int test ( void )
{
return(fun(1,2,3));
}当前使用gnu的结果是
00000000 <test>:
0: e92d4010 push {r4, lr}
4: e3a02003 mov r2, #3
8: e3a01002 mov r1, #2
c: e3a00001 mov r0, #1
10: ebfffffe bl 0 <fun>
14: e8bd4010 pop {r4, lr}
18: e12fff1e bx lr编译器和目标的每个组合都可能有不同的调用约定,因此没有理由假定同一编译器的不同编译器或版本使用相同的约定。ARM,MIPS,以及毫无疑问的其他人试图帮助/鼓励/建议使用一个调用约定,而一些编译器只是遵循这一点,为什么不这样做呢?
在约定中,规则有很多例外情况,但是对于ARM来说,前四个寄存器的参数值最多为4个,在这种情况下,最多为4个有符号或无符号整数,或至多4个小于或等于32位量的整数(浮点数可创建异常),前四个通用的回归器用于第一个参数r0,用于第二个参数,依此类推。目前,标准在64位边界上保持堆栈对齐。
所以我们看到,第一个参数确实放在r0中,第二个参数放在r1中,第三个参数放在r2中,很明显,您不必按照这个顺序排列这三个指令,这并不重要。
因为这个函数正在调用另一个函数,它必须在lr中保留它的返回值,所以它会在堆栈上保持堆栈对齐,因为标准说,为了在64位边界上保持堆栈对齐,他们在堆栈r4上推送另一个寄存器是任意的,它可以是任意的寄存器,这是工具选择的寄存器。
因为标准要求在r0中返回,所以实现这些函数之一的代码。
unsigned int fun ( unsigned int a, unsigned int b, unsigned int c )
{
return(a+b^c);
}
00000000 <fun>:
0: e0800001 add r0, r0, r1
4: e0200002 eor r0, r0, r2
8: e12fff1e bx lr现在非常有趣的是,我看到编译器没有对调用进行尾优化,它可能没有保存lr,并且做了一个分支来好玩,因为r0中的返回值也是test()在同一个寄存器中返回的。真的有点困惑,因为没有发生这种事。
但是您可以看到返回值确实保留在r0中,按照惯例,我们不需要保存r0-r3,而这些函数不是。
如果您将测试更改为
unsigned int fun ( unsigned int a, unsigned int b, unsigned int c );
unsigned int test ( void )
{
return(fun(1,2,3)+7);
}然后,它不能尾巴优化,也显示返回寄存器,所以你不必创建一个有趣()函数来查看它。
00000000 <test>:
0: e92d4010 push {r4, lr}
4: e3a02003 mov r2, #3
8: e3a01002 mov r1, #2
c: e3a00001 mov r0, #1
10: ebfffffe bl 0 <fun>
14: e8bd4010 pop {r4, lr}
18: e2800007 add r0, r0, #7
1c: e12fff1e bx lr您可以使用其他目标或其他编译器来做这种事情,没有理由假设一个目标和另一个目标具有相同的约定。
Disassembly of section .text:
00000000 <fun>:
0: 0f 5e add r14, r15
2: 0f ed xor r13, r15
4: 30 41 ret
0000000000000000 <fun>:
0: 8d 04 37 lea (%rdi,%rsi,1),%eax
3: 31 d0 xor %edx,%eax
5: c3 retq 这个是基于堆栈的,而不是基于寄存器的。
Disassembly of section .text:
00000000 <_fun>:
0: 1166 mov r5, -(sp)
2: 1185 mov sp, r5
4: 1d41 0004 mov 4(r5), r1
8: 6d41 0006 add 6(r5), r1
c: 1d40 0008 mov 10(r5), r0
10: 7840 xor r1, r0
12: 1585 mov (sp)+, r5
14: 0087 rts pc但是,如果这只是一个纯粹的组装项目,并且您不需要与编译后的输出进行接口,那么您想做什么就做什么,设计项目的一部分不仅仅是每个单独的函数,而是它们的交互方式,与C、Python或其他语言没有什么不同,您仍然需要为自己定义函数之间的接口。汇编语言并不是特别的或不同的,只是另一种语言而已。
https://stackoverflow.com/questions/35943763
复制相似问题