I have two macros, one is written in assembly and the other in C. The second macro uses the first macro. However, I also want to write the second macro in assembly with volatile, so I can control its placement in the code. And please note that tid is a runtime value, not a constant like n.
What is a good way to write that in assembly? Also, is it possible to control placement of a C code like assembly with volatile?
#define SAVE_SP(n) __asm__ __volatile__ ("movq %rsp, msp"#n";" \
"movq ts"#n", %rsp;" \
)
#define SAVE_STACK_POINTER( tid ) \
switch( tid ) \
{ \
case 0: \
SAVE_SP( 0 ); \
break; \
case 1: \
SAVE_SP( 1 ); \
break; \
case 2: \
SAVE_SP( 2 ); \
break; \
case 3: \
SAVE_SP( 3 ); \
break; \
}
In assembly, comments are usually denoted by a semicolon ; , although GAS uses # for single line comments and /* … */ for block comments possibly spanning multiple lines.
RESB , RESW , RESD , RESQ and REST are designed to be used in the BSS section of a module: they declare uninitialised storage space. Each takes a single operand, which is the number of bytes, words, doublewords or whatever to reserve.
The definition of an assembly is a grouping of people together typically for a specific reason. An example of an assembly is a musical performance by the orchestra at an elementary school.
You can ask gcc its idea of how to write your code in assembly: gcc -S foo.c
or gcc -Wa,-alh=foo.s -c foo.c
. You may want to improve on the results, of course. You will need to do a little extra: use %0
for the parameter that you pass for the assembly chunk, and declare the registers that you've clobbered. Look up Assembler Instructions with C Expression Operands in the GCC manual if you aren't familiar. Here's how this might look like (warning, typed directly into the browser, and don't really know x86 assembly syntax).
#define SAVE_STACK_POINTER(tid) __asm__ __volatile__ (" \
cmpl $0, %0 \n\
je .SAVE_STACK_POINTER_0 \n\
cmpl $1, %0 \n\
je .SAVE_STACK_POINTER_1 \n\
cmpl $2, %0 \n\
je .SAVE_STACK_POINTER_2 \n\
cmpl $3, %0 \n\
je .SAVE_STACK_POINTER_3 \n\
jmp .SAVE_STACK_POINTER_done \n\
.SAVE_STACK_POINTER_0: \n\
movq %%rsp, msp0 \n\
movq ts0, %%rsp \n\
jmp SAVE_STACK_POINTER_done \n\
.SAVE_STACK_POINTER_1: \n\
movq %%rsp, msp1 \n\
movq ts1, %%rsp \n\
jmp SAVE_STACK_POINTER_done \n\
.SAVE_STACK_POINTER_2: \n\
movq %%rsp, msp2 \n\
movq ts2, %%rsp \n\
jmp SAVE_STACK_POINTER_done \n\
.SAVE_STACK_POINTER_3: \n\
movq %%rsp, msp3 \n\
movq ts3, %%rsp \n\
.SAVE_STACK_POINTER_done: \n\
" : : "r" (tid))
A fancier method would involve figuring out how many bytes each movq
-movq
-jmp
block takes (note: I haven't checked, I use 8) and making a computed jump into it; something like
__asm__(" \n\
movl %0, %eax \n\
mul 8, %eax \n\
add 4, %eax \n\
jmp . + %eax \n\
movq %%rsp, msp0 \n\
movq ts0, %%rsp \n\
jmp .SAVE_STACK_POINTER_done \n\
…
.SAVE_STACK_POINTER_done: \n\
" : : "r" (tid) : "%eax")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With