SPRUI04F july 2015 – april 2023
Calls a Function
.call [ret_reg=] func_name ([argument1, argument2,...])
Use the .call directive to call a function. Optionally, you can specify a register that is assigned the result of the call. The register can be a symbolic or machine register. The .call directive adheres to the same register and function calling conventions as the C/C++ compiler. For information, see Section 8.3 and Section 8.4. There is no support for alternative register or function calling conventions.
You cannot call a function that has a variable number of arguments, such as printf. No error checking is performed to ensure the correct number and/or type of arguments is passed. You cannot pass or return structures through the .call directive.
Following is a description of the .call directive parameters:
ret_reg | (Optional) Symbolic/machine register that is assigned the result of the call. If not specified, the assembly optimizer presumes the call overwrites the registers A5 and A4 with a result. | |
func_name | The name of the function to call, or the name of the symbolic/ machine register for indirect calls. A register pair is not allowed. The label of the called function must be defined in the file. If the code for the function is not in the file, the label must be defined with the .global or .ref directive (refer to the TMS320C6000 Assembly Language Tools User's Guide for details). If you are calling a C/C++ function, you must use the appropriate linkname of that function. See Section 7.12 for more information. | |
arguments | (Optional) Symbolic/machine registers passed as an argument. The arguments are passed in this order and cannot be a constant, memory reference, or other expression. |
By default, the compiler generates near calls and the linker utilizes trampolines if the near call will not reach its destination. To force a far call, you must explicitly load the address of the function into a register, and then issue an indirect call. For example:
MVK func,reg
MVKH func,reg
.call reg(op1) ; forcing a far call
If you want to use * for indirection, you must abide by C/C++ syntax rules, and use the following alternate syntax:
.call [ret_reg =] (* ireg)([arg1, arg2,...])
For example:
.call (*driver)(op1, op2) ; indirect call
.reg driver
.call driver(op1, op2) ; also an indirect call
Here are other valid examples that use the .call syntax.
.call fir(x, h, y) ; void function
.call minimal( ) ; no arguments
.call sum = vecsum(a, b) ; returns an int
.call hi:lo = _atol(string) ; returns a long
Since you can use machine register names anywhere you can use symbolic registers, it may appear you can change the function calling convention. For example:
.call A6 = compute()
It appears that the result is returned in A6 instead of A4. This is incorrect. Using machine registers does not override the calling convention. After returning from the compute function with the returned result in A4, a MV instruction transfers the result to A6.
Here is a complete .call example:
.global _main
.global _puts, _rand, _ltoa
.sect ".const"
string1: .string "The random value returned is ", 0
string2: .string " ", 10, 0 ; '10' == newline
.bss charbuf, 20
.text
_main: .cproc
.reg random_value, bufptr, ran_val_hi:ran_val_lo
.call random_value = _rand() ; get a random value
MVKL string1, bufptr ; load address of string1
MVKH string1, bufptr
.call _puts(bufptr) ; print out string1
MV random_value, ran_val_lo
SHR ran_val_lo, 31, ran_val_hi ; sign extend random value
.call _ltoa(ran_val_hi:ran_val_lo, bufptr) ; convert it to a string
.call _puts(bufptr) ; print out the random value
MVKL string2, bufptr ; load address of string2
MVKH string2, bufptr
.call _puts(bufptr) ; print out a newline
.endproc