This is a code I used to write some data in memory for debugging (until printf is available in u-boot program). Variable myptr
is located in .__mydebug
section and it is incremented by 8 after every 8-byte write and I want to write any value I'm interested in in the form of {debug_tag, debug_value}
pair. Here debug_tag
is some value to show the debug data sequence, and the debug_value
is the value I want to check(or see) during the debug. This is arm64 assembly.
.global myptr
ldr x28, =myptr /* load the address of myptr */
add x28, x28, #8 /* set write pointer to the next address after the myptr variable */
mov x27, #0x33 /* first debug write starts with tag value 0x33 */
str x27, [x28], #8 /* write the tag value, increment the pointer */
mov x27, some_value /* some_value : the value I want to see with tag value 0x33 */
str x27, [x28], #8 /* write the debug value, increment the pointer */ ldr x26, =myptr /* load pointer address */
/* next debug write, in the same assembly code, x28 hasn't changed, so use as is */
mov x27, #0x34 /* new debug tag */
str x27, [x28], #8 /* write new tag, increment pointer */
mov x27, some_another_value /* another data I want to check */
str x27, [x28], #8 /* write the data, increment pointer */
ldr x26, =myptr /* load the address of myptr to x26 */
str x28, [x26] /* save the updated pointer in myptr, just in case x28 is modified and \
the pointer should be used later in assembly or C code .. */
.... (skip) ....
.section .__mydebug
myptr: .double 0x0
data_start: .double 0x0
So this is sequentially writing debug info in a memory section which works.
I can continue this debug write later in a .c program as below and it also works.
// debug print
int xx=sizeof(struct global_data);
*((uint64_t *)myptr) = 0x101; myptr+=8; /* debug tag start with 0x101 here */
*((uint64_t *)myptr) = xx; myptr+=8; /* write some data I want to check.. */
*((uint64_t *)myptr) = 0x102; myptr+=8; /* another debug tag */
*((uint64_t *)myptr) = base; myptr+=8; /* another value I want to check */
Ok, I can live with that. But this doesn't look nice and inconvenient.
So I'm curious how I can do the above in C program using a function with inline assembly. I want to pass to the function the tag value and the debug value(64-bit) as arguments. The function should retrieve the myptr
value to write the tag and data and should update the myptr
value each time. I tried writing a function below.
void dbg_print(unsigned int tag, uint64_t data)
{
uint64_t ptr_addr1;
__asm (
"ldr %[ptr_addr], =myptr" \
"ldr %[ptr_val], [%[ptr_addr]]" \
"str %[tag_val], [%[ptr_val]], #8" \
"str %[data_val], [%[ptr_val]], #8"
: /* no output */ \
: [tag_val] "r" (tag), [data_val] "r" (data) /* input list */ \
: "memory" /* no specific clobbered register, but memory modified */
);
}
When I compile it, I get this compile error.
common/init/board_init.c: In function 'dbg_print':
common/init/board_init.c:144:1: error: undefined named operand 'ptr_addr'
144 | );
| ^
common/init/board_init.c:144:1: error: undefined named operand 'ptr_val'
common/init/board_init.c:144:1: error: undefined named operand 'ptr_addr'
common/init/board_init.c:144:1: error: undefined named operand 'ptr_val'
common/init/board_init.c:144:1: error: undefined named operand 'ptr_val'
make[2]: *** [scripts/Makefile.build:254: spl/common/init/board_init.o] Error 1
make[1]: *** [scripts/Makefile.spl:515: spl/common/init] Error 2
I can't understand undefined named operand
error. Do I need to define the operand in the template somewhere? In the example in https://www.keil.com/support/man/docs/armclang_ref/armclang_ref_qbn1517569205870.htm, the operands in the template are just used without defining. The variables in C is declared anyway but aren't the operands in the assembly template substituted by the compiler anyway?
Thank you for reading and I would be grateful if someone could clarify this thing to me.
ADD :
Having read Nate Eldredge and Peter Cordes's comments, I realized 'defining the operand' means to connect the value into the C world using the operand specifiers (those fields after : and connected with :). So I tried changing the code to this and I'll see if this works.
void dbg_print(unsigned int tag, uint64_t data)
{
uint64_t ptra, ptrv;
__asm (
"ldr %[ptr_addr], =myptr \n" /* get pointer address */
"ldr %[ptr_val], [%[ptr_addr]] \n" /* get pointer value */
"str %[tag_val], [%[ptr_val]], #8 \n" /* write to pointed addr */
"str %[data_val], [%[ptr_val]], #8 \n" /* write to pointed addr */
: [ptr_addr] "=r" (ptra), [ptr_val] "=r" (ptrv)
: [tag_val] "r" (tag), [data_val] "r" (data) /* input list */
: "memory" /* no specific clobbered register, but memory modified */
);
}