Inline assembly: clarification of constraint modifiers - c

Two questions:
(1) If I understand ARM inline assembly correctly, a constraint of "r" says that the instruction operand can only be a core register and that by default is a read-only operand. However, I've noticed that if the same instruction has an output operand with the constraint "=r", the compiler may re-use the same register. This seems to violate the "read-only" attribute. So my question is: Does "read-only" refer to the register, or to the C variable that it is connected to?
(2) Is it correct to say that presence of "&" in the constraint of "=&r" simply requires that the register chosen for the output operand must not be the same as one of the input operand registers? My question relates to the code below used to compute the integer power function: i.e., are the "&" constraint modifiers necessary/appropriate?
asm (
" MOV %[power],1 \n\t"
"loop%=: \n\t"
" CBZ %[exp],done%= \n\t"
" LSRS %[exp],%[exp],1 \n\t"
" IT CS \n\t"
" MULCS %[power],%[power],%[base] \n\t"
" MUL %[base],%[base],%[base] \n\t"
" B loop%= \n\t"
"done%=: "
: [power] "+&r" (power)
[base] "+&r" (base)
[exp] "+&r" (exp)
:
: "cc"
) ;
Thanks!
Dan

Read-only refers to the use of the operand in assembly code. The assembly code can only read from the operand, and it must do so before any normal output operand (not an early clobber or a read/write operand) is written. This is because, as you've seen, the same register can be allocated to both an input and output operand. The assumption is that inputs are fully consumed before any output is written, which is normally the case for an assembly instruction.
I don't think using an early-clobber modifier & with an read/write modifier + has any effect since a register allocated to a read/write operand can't be used for anything else.
Here's how I'd write your code:
unsigned power = 1;
asm (
" CBZ %[exp],done%= \n\t"
"loop%=: \n\t"
" LSRS %[exp],%[exp],1 \n\t"
" IT CS \n\t"
" MULCS %[power],%[power],%[base] \n\t"
" MUL %[base],%[base],%[base] \n\t"
" BNE loop%= \n\t"
"done%=: "
: [power] "+r" (power),
[base] "+r" (base),
[exp] "+r" (exp)
:
: "cc"
) ;
Note the transformation of putting the loop test at the end of the loop, saving one instruction. Without it the code doesn't have any obvious improvement over what the compiler can generate. I also let the compiler do the initialization of the register used for the power operand. There's a small chance it will be able to allocate a register that already has the value 1 in it.

Thanks to all of you for the clarification. Just to be sure that I have it right, would it be correct to say that the choice between "=r" and "+r" for an output operand comes down to how the corresponding register is first used in the assembly template? I.e.,
"=r": The first use of the register is as a write-only output of an instruction.
The register may be re-used later by another instruction as an input or output. Adding an early clobber constraint (e.g., "=&r") prevents the compiler from assigning a register that was previously used as an input operand.
"+r": The first use of the register is as an input to an instruction, but the register is used again later as an output.
Best,
Dan

Related

How do I access a local variable using ARM assembly language?

I use the following piece of assembly code to enter the critical section in ARM Cortex-M4.
The question is, how can I access the local variable primeMask?
volatile uint8_t primaskValue;
asm(
"MRS R0, PRIMASK \n"
"CPSID i \n"
"STRB R0,%[output] \n"
:[output] "=r" (primaskValue)
);
The %[output] string in the asm code is replaced by the register used to hold the value specified by the constraint [output] "=r" (primaskValue) which will be a register used as the value of primaskValue afterwards. So within the block of the asm code, that register is the location of primaskValue.
If you instead used the constraint string "+r", that would be input and output (so the register would be initialized with the prior value of primaskValue as well as being used as the output value)
Since primaskValue had been declared as volatile this doesn't make a lot of sense -- it is not at all clear what (if anything) volatile means on a local variable.

C embedded assembly error: ‘asm’ operand has impossible constraints

When I embedded assembly in C language, I met the following error compiling these code using a shell command in ubuntu linux 14.04.
IFR_temp_measure.cpp: In function ‘void BlockTempClc(char*, char*,
int, int, char, int, int, int, int*, int, int*, int)’:
IFR_temp_measure.cpp:1843:6: error: ‘asm’ operand has impossible
constraints);
^
&make: *** [IFR_temp_measure.o] Error 1
or the position of the error code line 1842,1843 is respond to the code
:"cc", "memory","q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q10", "q11", "q12", "q13", "q14", "q15","r0", "r1", "r3", "r4", "r5","r6","r8", "r9", "r10", "r12"
);
I have tried to solve this problem,but Few references are available online,there is a linker:
Gcc inline assembly what does "'asm' operand has impossible constraints" mean? and http://www.ethernut.de/en/documents/arm-inline-asm.html
but not helped.
My code is as follows:
void BlockTempClc(char* src1,char* src2,int StrideDist,int height,char temp_comp1,int numofiterations,int temp_comp2,int temp_comp3,int *dstData,int width,int *dstSum,int step)
{
volatile char array1[16] = {0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0};
volatile char array2[16] = {0,0,1,0,2,0,3,0,
4,0,5,0,6,0,7,0};
asm volatile(
"mov r0, %0; " //image[0]
"mov r1, %1; " //image[1]
"mov r12,%11; " //m
"mov r3, %4; " //n
"mov r4, %2; " //store data
"mov r8, %12; " //step down for loading next line of image
"mov r5, %6; " //numofiterations
"mov r6, %3; " //out
"mov.8 r9,%5;"//isp_temp_comp
"mov.8 r10,%7;"//led_temp_comp
"mov.8 r11,%8;"//fac_temp_comp
"vdup.8 d20,r9;"//copy arm register value isp_temp_comp to neon register
"VMOV.S16 q9, d20; " //isp_temp_comp transfer to signed short type
"VLD1.8 {d16,d17}, [%9];"//q8 array1 sum
"VLD1.8 {d6,d7}, [%10];"//q3 array2
"VMOV.S16 q0, #256; "
"VMOV.S16 q1, #2730; " //Assign immediate number 2730 to each 16 bits of d1
".loop:;"
"vdup.8 d21,r10;"//copy arm register value led_temp_comp to neon register
"vdup.8 d22,r11;"//copy arm register value fac_temp_comp to neon register
"VLD1.8 d14, [r1],r8; " // q7 *(image[1] + tmp + n) Load: Load Picture Pixels r6:move step ?
"VLD1.8 d15, [r0],r8 " // *(image[0] + tmp + n) Load: Load Picture Pixels
"PLD [r1]; " //Preload: one line in cache
"PLD [r0]; " //?
"VMOV.S16 q5, d14; " //q5 8*16 transfer to signed short type:*(image[1] + tmp + n)
"VMOV.S16 q6, d15; " //q6 8*16 transfer to signed short type : *(image[0] + tmp + n)
"VADD.S16 q12,q6, q9;"//*(image[0] + tmp + n) + isp_temp_comp
"VMOV.S16 q6, d21; " //led_temp_comp
"VADD.S16 q13,q12, q6;"//*(image[0] + tmp + n) + isp_temp_comp+ + led_temp_comp
"VMOV.S16 q6, d22; " //fac_temp_comp
"VADD.S16 q14,q13, q6;"//*(image[0] + tmp + n) + isp_temp_comp+ + led_temp_comp+ fac_temp_comp
"VSUB.S16 q15,q14, q1;"//*(image[0] + tmp + n) + isp_temp_comp+ + led_temp_comp+ fac_temp_comp-2730
"VMLA.S16 q15, q5, q0;"//img_temp[m][n]=*(image[0] + tmp + n) + isp_temp_comp+ + led_temp_comp+ fac_temp_comp-2730+*(image[1] + tmp + n) *256
"VADD.S16 q2,q15, q8;"//sum
"VMOV.S16 q8, q2; " //q8
"vdup.8 d20,r3;"//n
"vdup.8 d21,r12;"//m
"VMOV.S16 q11, d20; " //n
"VMOV.S16 q10, d21; " //m
"VADD.S16 q4,q3, q11;"//(n,n+1,n+2,n+3,n+4,n+5,n+6,n+7)
"VADD.S16 q7,q3, q10;"//(m,m+1,m+2,m+3,m+4,m+5,m+6,m+7) q7
"VST1.16 {d30[0]}, [r4]!; "//restore img_temp[m][n] to pointer data
"VST1.16 {d14[0]}, [r4]!; "//restore m
"VST1.16 {d8[0]}, [r4]!; " //restore n
"VST1.16 {d30[1]}, [r4]!; "
"VST1.16 {d14[1]}, [r4]!; "
"VST1.16 {d8[1]}, [r4]!; "
"VST1.16 {d30[2]}, [r4]!; "
"VST1.16 {d14[2]}, [r4]!; "
"VST1.16 {d8[2]}, [r4]!; "
"VST1.16 {d30[3]}, [r4]!; "
"VST1.16 {d14[3]}, [r4]!; "
"VST1.16 {d8[3]}, [r4]!; "//response to array
"subs r5, r5, #1; " // decrement: numofinteration -= 1;
"bne .loop; " // Branch If Not Zero; to .loop
"VST1.16 {d4[0]}, [r6]!; "//q2 refer to sum restore the final result to pointer out
"VST1.16 {d4[1]}, [r6]!; "
"VST1.16 {d4[2]}, [r6]!; "
"VST1.16 {d4[3]}, [r6]!; "
"VST1.16 {d5[0]}, [r6]!; "
"VST1.16 {d5[1]}, [r6]!; "
"VST1.16 {d5[2]}, [r6]!; "
"VST1.16 {d5[3]}, [r6]!; "
:"+r"(src1),"+r"(src2),"+r"(dstData),"+r"(dstSum),"+r"(height)
:"r"(temp_comp1),"r"(numofiterations),"r"(temp_comp2),"r"(temp_comp3),
"r"(array1),"r"(array2), "r"(width),"r"(step)
:"cc", "memory","q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q10", "q11", "q12", "q13", "q14", "q15","r0", "r1", "r3", "r4", "r5","r6","r8", "r9", "r10", "r12"
);
}
I suppose the problem maybe output operands lists or output operands lists.
Whats cause the error of my code?and how to solve it?
You declare clobbers on most of the integer registers, but then you ask for 13 different input variables. 32-bit ARM only has 16 registers, and 2 of those are PC and SP leaving only 14 at best really general purpose registers.
We can test that too many clobbers + operands are the problem by removing all the clobbers on r0.. r12; this lets it compile (into incorrect code!!). https://godbolt.org/z/Z6x78N This is not the solution because it introduces huge bugs, it's just how I confirmed that this is the problem.
Any time your inline asm template starts with mov to copy from an input register operand into a hard-coded register, you're usually doing it wrong. Even if you had enough registers, the compiler is going to have to emit code to get the variable into a register, then your hand-written asm uses another mov to copy it for no reason.
See https://stackoverflow.com/tags/inline-assembly/info for more guides.
Instead ask the compiler for the input in that register in the first place with register int foo asm("r0"), or better let the compiler do register allocation by using %0 or the equivalent named operand like %[src1] instead of a hard-coded r0 everywhere inside your asm template. The syntax for naming an operand is [name] "r" (C_var_name). They don't have to match, but they don't have to be unique either; it's often convenient to use the same asm operand name as the C var name.
Then you can remove the clobbers on most of the GP registers. You do need to tell the compiler about any input registers you modify, e.g. by using a "+r" constraint instead of "r" (and then not using that C variable after the asm modifies it). Or use an "=r" output constraint and a matching input constraint like "0" (var) to put that input in the same register as output operand 0. "+r" is much easier in a wrapper function where the C variable is not used afterwards anyway.
You can remove the clobbers on vector registers if you use dummy output operands to get the compiler to do register allocation, but it's basically fine if you just leave those hard-coded.
asm( // "mov r0, %[src1]; " // remove this and just use %[src1] instead of r0
"... \n\t"
"VST1.16 {d30[0]}, [%[dstData]]! \n\t" //restore img_temp[m][n] to pointer data
"... \n\t"
: [src1]"+&r"(src1), [src2]"+&r"(src2), [dstData]"+&r"(dstData),
[dstSum]"+&r"(dstSum), [height]"+&r"(height)
: [temp_comp1] "r"(temp_comp1), [niter] "r"(numofiterations),
[temp_comp2] "r"(temp_comp2), [temp_comp3] "r"(temp_comp3),
...
: "memory", "cc", all the q and d regs you use. // but not r0..r13
);
You can look at the compiler's asm output to see how it filled in the %0 and %[name] operands in the asm template you gave it. Use "instruction \n\t" to make this readable, ; puts all the instructions onto the same line in the asm output. (C string-literal concatenation doesn't introduce newlines).
The early-clobber declarations on the read/write operands makes sure that none of the input-only operands share a register with them, even if they have the compiler knows that temp_comp1 == height for example. Because the original value of temp_comp1 still needs to be readable from the register %[temp_comp1], even after something has modified %[height]. So they can't both be r4 for example. Otherwise, without the & in "+&r", the compiler could choose that to gain efficiency if outputs are only written after all inputs are read. (e.g. when wrapping a single instruction, like GNU C inline asm is designed to do efficiently).
side-note: char array1[16] and 2 don't need to be volatile; the "memory" clobber on the asm statement is sufficient even though you just pass pointers to them, not use them as "m" input operands.

Operands mismatch for mul when inserting asm into c

I'm trying to make an assembly insert into C code. However when I try to multiply two registers inside it I get an error calling for operands mismatch. I tried "mul %%bl, %%cl\n" (double %% because it's in C code). From my past experience with asm I think this should work. I also tried "mul %%cl\n" (moving bl to al first), but in this case I get tons of errors from linker
zad3:(.rodata+0x4): multiple definition of `len'
/tmp/ccJxYyIp.o:(.rodata+0x0): first defined here
zad3: In function `_fini':
(.fini+0x0): multiple definition of `_fini'
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o:(.fini+0x0): first defined here
zad3: In function `data_start':
(.data+0x0): multiple definition of `__data_start'
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o:(.data+0x0): first defined here
zad3: In function `data_start':
(.data+0x8): multiple definition of `__dso_handle'
/usr/lib/gcc/x86_64-linux-gnu/5/crtbegin.o:(.data+0x0): first defined here
zad3:(.rodata+0x0): multiple definition of `_IO_stdin_used'
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o:(.rodata.cst4+0x0): first defined here
zad3: In function `_start':
(.text+0x0): multiple definition of `_start'
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o: (.text+0x0): first defined here
zad3: In function `data_start':
(.data+0x10): multiple definition of `str'
/tmp/ccJxYyIp.o:(.data+0x0): first defined here
/usr/bin/ld: Warning: size of symbol `str' changed from 4 in /tmp/ccJxYyIp.o to 9 in zad3
zad3: In function `main':
(.text+0xf6): multiple definition of `main'
/tmp/ccJxYyIp.o:zad3.c:(.text+0x0): first defined here
zad3: In function `_init':
(.init+0x0): multiple definition of `_init'
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o:(.init+0x0): first defined here
/usr/lib/gcc/x86_64-linux-gnu/5/crtend.o:(.tm_clone_table+0x0): multiple definition of `__TMC_END__'
zad3:(.data+0x20): first defined here
/usr/bin/ld: error in zad3(.eh_frame); no .eh_frame_hdr table will be created.
collect2: error: ld returned 1 exit status
From what I understand, it tells me I defined len and a few other variables a few times, but I cannot see this multiple definition.
The goal of my program is to take a string of numbers and count sum of them but using 2 as a base. So let's say string is 293, then I want to count 2*2^2+9*2^1+3*2^0
Code:
#include <stdio.h>
char str[] = "543";
const int len = 3;
int main(void)
{
asm(
"mov $0, %%rbx \n"
"mov $1, %%rcx \n"
"potega: \n"
"shl $1, %%cl \n"
"inc %%rbx \n"
"cmp len, %%ebx \n"
"jl potega \n"
"mov $0, %%rbx \n"
"petla: \n"
"mov (%0, %%rbx, 1), %%al \n"
"sub $48, %%al \n"
"mul %%al, %%cl \n"
"shr $1, %%cl \n"
"add $48, %%al \n"
"mov %%al, (%0, %%rbx, 1) \n"
"inc %%rbx \n"
"cmp len, %%ebx \n"
"jl petla \n"
:"r"(&str)
:"%rax", "%rbx", "%rcx"
);
printf("Wynik: %s\n", str);
return 0;
}
While I try to avoid "doing people's homework" for them, you have already solved this and given that it has been over a week, have probably already turned it in.
So, looking at your final solution, there are a few things you might want to consider doing differently. In no particular order:
Comments. While all code needs comments, asm REALLY needs comments. As you'll see from my solution (below), having comments alongside the code really helps clarify what the code does. It might seem like a homework project hardly needs them. But since you posted this here, 89 people have tried to read this code. Comments would have made this easier for all of us. Not to mention that it will make life easier for your 'future self,' when you come back months from now to try to maintain it. Comments. Nuff said.
Zeroing registers. While mov $0, %%rbx will indeed put zero in rbx, this is not the most efficient way to zero a register. Using xor %%rbx, %%rbx is both (microscopically) faster and produces (slightly) smaller executable code.
potega. Without comments, it took me a bit to sort out what you were doing in your first loop. You are using rbx to keep track of how many characters you have processed, and cl gets shifted one to the left for each character. A few thoughts here:
3a. First thing I'd do is look at moving the shl $1, %%cl out of the loop. Instead of doing both increment and shift, just count the characters, then do a single shift of the appropriate size. This is (slightly) complicated by the fact that if you want to shift by a variable amount, the amount must be specified in cl (ie shl %%cl, %%rbx). Why cl? Who knows? That's just how shl works. So you'd want to do the counting in cl instead of rbx.
3b. Second thing about this loop has to do with len1. Since you already know the size (it's in len1), why would you even need a loop? Perhaps a more sensible approach would be:
3c. Strings in C are terminated with a null character (aka 0). If you want to find the length of a string, normally you'd walk the string until you find it. This removes the requirement to even have len1.
3d. Your code assumes that the input string is valid. What would happen if you got passed "abc"? Or ""? Validating parameters is boring, time consuming, and makes the program bigger and run slower. On the other hand, it pays HUGE dividends when something unexpected goes wrong. At the very least you should specify your assumptions about your input.
3e. Using global variables is usually a bad idea. You run into naming collisions (2 files both using the name len1), code in several different files all changing the value (making bugs difficult to track down) and it can make your program bigger than it needs to be. There are times when globals are useful, but this does not appear to be one of them. The only purpose here seems to be to allow access to these variables from within the asm, and there are other ways to do that.
3f. You use %0 to refer to str. That works (and is better than accessing the global symbol directly), but it is harder to read than it needs to be. You can associate a name with the parameter and use that instead.
Let's take a break for a moment to see what we've got so far:
"xor %%rcx, %%rcx\n" // Zero the strlen count
// Count how many characters in string
"potega%=: \n\t"
"mov (%[pstr], %%rcx), %%bl\n\t" // Read the next char
"test %%bl, %%bl \n\t" // Check for 0 at end of string
"jz kont%= \n\t"
"cmp $'0', %%bl\n\t" // Ensure digit is 0-9
"jl gotowe%=\n\t"
"cmp $'9', %%bl\n\t"
"jg gotowe%=\n\t"
"inc %%rcx \n\t" // Increment index/len
"jmp potega%= \n"
"kont%=:\n\t"
// rcx = the number of character in the string excluding null
You'll notice that I'm using %= at the end of all the labels. You can read about what this does in the gcc docs, but mostly it just appends a number to the labels. Why do that? Well, if you wanted to try computing multiple strings in a single run (like I do below), you might call this code several times. But compilers (being the tricky devils that they are) might choose to "inline" your assembler. That would mean you'd have several chunks of code that all had the same label names in the same routine. Which would cause your compile to fail.
Note that I don't check to see if the string is "too long" or NULL. Left as an exercise for the student...
Ok, what else?
petla. Mostly my code matches yours.
4a. I did change to sub $'0', %%al instead of just using $48. It does the same thing, but subtracting '0' seems to me to be more "self-documenting."
4b. I also slightly reordered things to put the shr at the end. Why do that? You use cmp along with jz to see when it's time to exit the loop. The way cmp works is that it sets some flags in the flags register, then jz looks at those flags to figure out whether to jump or not. However shr sets those flags too. Each time you shift, you are moving that '1' further and further to the right. What happens when it's at the rightmost position and you shift it 1 more? You get zero. At which point the "jump if not zero" (aka jnz) works as expected. Since you have to do the shr anyway, why not use it to tell you when to exit the loop too?
That gives me:
"petla%=:\n\t"
"mov (%[pstr], %%rcx, 1), %%al\n\t" // read the next char
"sub $'0', %%al\n\t" // convert char to value
"mul %%bl\n\t" // mul bl * al -> ax
"add %%ax, %[res]\n\t" // Accumulate result
"inc %%rcx\n\t" // move to next char
"shr $1, %%rbx\n\t" // decrease our exponent
"jnz petla%=\n" // Has our exponent gone to 0?
"gotowe%=:"
Lastly, the parameters:
:[res] "=r"(result)
:[pstr] "r"(str), "0"(0)
:"%rax", "%rbx", "%rcx", "cc"
I'm going to store the result in the C variable named result. Since I specify =r with this constraint, I know that it is stored in a register, although I don't know which register the compiler will pick. But I don't need to. I can just refer to it using %[res] and let the compiler sort it out. Likewise I refer to the string using %[pstr]. I could use %0 like you did, except that since I've added result, pstr isn't %0 anymore, it's %1 (result is now %0). This is another reason to use names instead of numbers.
That last bit ("0"(0)) might take a bit of explaining. Using "0" for the constraint (instead of say "r") tells the compiler to put this value into the same place as parameter #0. The (0) says store a zero there before starting the asm. In other words, initialize the register that is going to hold result to 0. Yes, I could do this in the asm. But I prefer to let the compiler do this for me. While it may not matter in a tiny program like this, letting the C compiler do as much work as possible tends to produce the most efficient code.
So, when we wrap this all together, I get:
/*
my_file.c - The goal of this program is to take a string of numbers and
count sum of them but using 2 as a base.
example: "543" -> 5*(2^2)+4*(2^1)+3*(2^0)=31
*/
#include <stdio.h>
void TestOne(const char *str)
{
short result;
// Code assumes str is not NULL. Strings with non-digits and zero
// length strings return 0.
asm(
"xor %%rcx, %%rcx\n" // Zero the strlen count
// Count how many characters in string
"potega%=: \n\t"
"mov (%[pstr], %%rcx), %%bl\n\t" // Read the next char
"test %%bl, %%bl \n\t" // Check for 0 at end of string
"jz kont%= \n\t"
"cmp $'0', %%bl\n\t" // Ensure digit is 0-9
"jl gotowe%=\n\t"
"cmp $'9', %%bl\n\t"
"jg gotowe%=\n\t"
"inc %%rcx \n\t" // Increment index/len
"jmp potega%= \n"
"kont%=:\n\t"
// rcx = the number of character in the string excluding null
"dec %%rcx \n\t" // We want to shift rbx 1 less than pstr length
"jl gotowe%=\n\t" // Check for zero length string
"mov $1, %%rbx\n\t" // Set exponent for first digit
"shl %%cl, %%rbx\n\t"
"xor %%rcx, %%rcx\n" // Reset string index
"petla%=:\n\t"
"mov (%[pstr], %%rcx, 1), %%al\n\t" // read the next char
"sub $'0', %%al\n\t" // convert char to value
"mul %%bl\n\t" // mul bl * al -> ax
"add %%ax, %[res]\n\t" // Accumulate result
"inc %%rcx\n\t" // move to next char
"shr $1, %%rbx\n\t" // decrease our exponent
"jnz petla%=\n" // Has our exponent gone to 0?
"gotowe%=:"
:[res] "=r"(result)
:[pstr] "r"(str), "0"(0)
:"%rax", "%rbx", "%rcx", "cc"
);
printf("Wynik: \"%s\" = %d\n", str, result);
}
int main(){
TestOne("x");
TestOne("");
TestOne("5");
TestOne("54");
TestOne("543");
TestOne("5432");
return 0;
}
Notice: No global variables. And no len1. Just a pointer to the string.
It might be interesting to experiment and see how long a string you can support. Using mul %%bl, add %%ax and short result works for tiny strings like these, but will eventually be insufficient as the strings get longer (requiring eax or rax etc). I'll leave that for you too. Warning: There's a trick when moving 'up' from mul %%bl to mul %%bx.
One last point about letting the compiler do as much work as possible tends to produce the most efficient code: Sometimes people assume that since they are writing assembler, this will result in faster code than if they write it in C. However, these people fail to take into account the fact that the entire purpose of a C compiler is to turn your C code into assembler. When you turn on optimization (-O2), the compiler is almost certainly going to turn your (well-written) C code into better assembler code than anything you can write by hand.
There are thousands of tweaks and tricks like the ones I've mentioned here. And the people who write compilers know them all. While there are a few places where inline asm can make sense, smart programmers leave this work to the lunatics who write compilers whenever possible. See also this.
I realize this is just a school project and you are only doing what your teacher requires, but since she has elected to use the most difficult way possible to teach you asm, perhaps she failed to mention that the thing you are doing is something you should (almost) never do in real life.
This post turned out longer than I expected. Hopefully there is information here that you can use. And forgive my attempts at Polish labels. Hopefully I haven't said anything obscene...
As somebody pointed out - yes it's a student exercise.
When it comes to my original problem, when I removed line add $48,%%al \n" it worked. I also switched to mul %%cl.
When it comes to rest of problems, you pointed out, I talked with my professor and she slightly changed her mind (or I got the assgment wrong the first time - whatever you find more possible) and now she wanted me to return an argument from the inline function and said the intiger type was good. It resulted in me writing such piece of code (which actually does what I wanted)
example: "543" -> 5*(2^2)+4*(2^1)+3*(2^0)=31
#include <stdio.h>
char str[] = "543";
const int len = 3;
int len1 = 2;
int result;
int main(){
asm(
"mov $0, %%rbx\n"
"mov $1, %%rcx\n"
"mov $0, %%rdx\n"
"potega: \n"
"inc %%rbx\n"
"shl $1, %%cl\n"
"cmp len1, %%ebx \n"
"jl potega\n"
"mov $0, %%rbx\n"
"petla:\n"
"mov (%0, %%rbx, 1), %%al\n"
"sub $48, %%al\n"
"mul %%cl\n"
"shr $1, %%cl\n"
"add %%al, %%dl\n"
"inc %%rbx\n"
"cmp len, %%ebx\n"
"jl petla\n"
"movl %%edx, result\n"
://"=r"(result)
:"r"(&str), "r"(&result)
:"%rax", "%rbx", "%rcx", "%rdx"
);
printf("Wynik: %d\n", result);
return 0;
}
Also - I do realise, that normally you return variables the way it's showed in comment, but it didn't work, so by my professor's suggestion I wrote the program this way.
Thanks everybody for help!

Using GCC inline assembly with instructions that take immediate values

The problem
I'm working on a custom OS for an ARM Cortex-M3 processor. To interact with my kernel, user threads have to generate a SuperVisor Call (SVC) instruction (previously known as SWI, for SoftWare Interrupt). The definition of this instruction in the ARM ARM is:
Which means that the instruction requires an immediate argument, not a register value.
This is making it difficult for me to architect my interface in a readable fashion. It requires code like:
asm volatile( "svc #0");
when I'd much prefer something like
svc(SVC_YIELD);
However, I'm at a loss to construct this function, because the SVC instruciton requires an immediate argument and I can't provide that when the value is passed in through a register.
The kernel:
For background, the svc instruction is decoded in the kernel as follows
#define SVC_YIELD 0
// Other SVC codes
// Called by the SVC interrupt handler (not shown)
void handleSVC(char code)
{
switch (code) {
case SVC_YIELD:
svc_yield();
break;
// Other cases follow
This case statement is getting rapidly out of hand, but I see no way around this problem. Any suggestions are welcome.
What I've tried
SVC with a register argument
I initially considered
__attribute__((naked)) svc(char code)
{
asm volatile ("scv r0");
}
but that, of course, does not work as SVC requires a register argument.
Brute force
The brute-force attempt to solve the problem looks like:
void svc(char code)
switch (code) {
case 0:
asm volatile("svc #0");
break;
case 1:
asm volatile("svc #1");
break;
/* 253 cases omitted */
case 255:
asm volatile("svc #255");
break;
}
}
but that has a nasty code smell. Surely this can be done better.
Generating the instruction encoding on the fly
A final attempt was to generate the instruction in RAM (the rest of the code is running from read-only Flash) and then run it:
void svc(char code)
{
asm volatile (
"orr r0, 0xDF00 \n\t" // Bitwise-OR the code with the SVC encoding
"push {r1, r0} \n\t" // Store the instruction to RAM (on the stack)
"mov r0, sp \n\t" // Copy the stack pointer to an ordinary register
"add r0, #1 \n\t" // Add 1 to the address to specify THUMB mode
"bx r0 \n\t" // Branch to newly created instruction
"pop {r1, r0} \n\t" // Restore the stack
"bx lr \n\t" // Return to caller
);
}
but this just doesn't feel right either. Also, it doesn't work - There's something I'm doing wrong here; perhaps my instruction isn't properly aligned or I haven't set up the processor to allow running code from RAM at this location.
What should I do?
I have to work on that last option. But still, it feels like I ought to be able to do something like:
__attribute__((naked)) svc(char code)
{
asm volatile ("scv %1"
: /* No outputs */
: "i" (code) // Imaginary directive specifying an immediate argument
// as opposed to conventional "r"
);
}
but I'm not finding any such option in the documentation and I'm at a loss to explain how such a feature would be implemented, so it probably doesn't exist. How should I do this?
You want to use a constraint to force the operand to be allocated as an 8-bit immediate. For ARM, that is constraint I. So you want
#define SVC(code) asm volatile ("svc %0" : : "I" (code) )
See the GCC documentation for a summary of what all the constaints are -- you need to look at the processor-specific notes to see the constraints for specific platforms. In some cases, you may need to look at the .md (machine description) file for the architecture in the gcc source for full information.
There's also some good ARM-specific gcc docs here. A couple of pages down under the heading "Input and output operands" it provides a table of all the ARM constraints
What about using a macro:
#define SVC(i) asm volatile("svc #"#i)
As noted by Chris Dodd in the comments on the macro, it doesn't quite work, but this does:
#define STRINGIFY0(v) #v
#define STRINGIFY(v) STRINGIFY0(v)
#define SVC(i) asm volatile("svc #" STRINGIFY(i))
Note however that it won't work if you pass an enum value to it, only a #defined one.
Therefore, Chris' answer above is the best, as it uses an immediate value, which is what's required, for thumb instructions at least.
My solution ("Generating the instruction encoding on the fly"):
#define INSTR_CODE_SVC (0xDF00)
#define INSTR_CODE_BX_LR (0x4770)
void svc_call(uint32_t svc_num)
{
uint16_t instrs[2];
instrs[0] = (uint16_t)(INSTR_CODE_SVC | svc_num);
instrs[1] = (uint16_t)(INSTR_CODE_BX_LR);
// PC = instrs (or 1 -> thumb mode)
((void(*)(void))((uint32_t)instrs | 1))();
}
It works and its much better than switch-case variant, which takes ~2kb ROM for 256 svc's. This func does not have to be placed in RAM section, FLASH is ok.
You can use it if svc_num should be a runtime variable.
As discussed in this question, the operand of SVC is fixed, that is it should be known to the preprocessor, and it is different from immediate Data-processing operands.
The gcc manual reads
'I'- Integer that is valid as an immediate operand in a data processing instruction. That is, an integer in the range 0 to 255 rotated by a multiple of 2.
Therefore the answers here that use a macro are preferred, and the answer of Chris Dodd is not guaranteed to work, depending on the gcc version and optimization level. See the discussion of the other question.
I wrote one handler recently for my own toy OS on Cortex-M. Works if tasks use PSP pointer.
Idea:
Get interrupted process's stack pointer, get process's stacked PC, it will have the instruction address of instruction after SVC, look up the immediate value in the instruction. It's not as hard as it sounds.
uint8_t __attribute__((naked)) get_svc_code(void){
__asm volatile("MSR R0, PSP"); //Get Process Stack Pointer (We're in SVC ISR, so currently MSP in use)
__asm volatile("ADD R0, #24"); //Pointer to stacked process's PC is in R0
__asm volatile("LDR R1, [R0]"); //Instruction Address after SVC is in R1
__asm volatile("SUB R1, R1, #2"); //Subtract 2 bytes from the address of the current instruction. Now R1 contains address of SVC instruction
__asm volatile("LDRB R0, [R1]"); //Load lower byte of 16-bit instruction into R0. It's immediate value.
//Value is in R0. Function can return
}

Help understanding DIV instruction in x86 inline assembly

While reading through some source code in a GNU project, I came across this bit of inline assembly:
__asm__ (
"divq %4"
: "=a" (q), "=d" (r)
: "0" (n0), "1" (n1), "rm" (d)
);
Here the variables q, r, n0, n1, and d are 64-bit integers. I know enough assembly to get the gist of what this does, but there's some details I'm not certain about.
What I understand:
We're dividing the contents of the RAX register by d, placing the quotient in q, and placing the remainder in r.
What I don't understand
Why are there three inputs
here? We only need to input a
dividend and a divisor, so what use
could there be for 3 inputs?
I can't tell which of the inputs is the dividend. More generally, I don't see anything actually
being loaded into the RAX register,
so how does it know what to divide by what?
In the input operands specification:
: "0" (n0), "1" (n1), "rm" (d)
registers "0" and "1" are forced to rax and rdx because of the output specification:
: "=a" (q), "=d" (r)
And the div instruction family wants the numerator in RDX:RAX. The divisor can be in a general purpose register (not otherwise used - ie., not RAX or RDX) or memory, which is specified by the "rm" constraint. Registers RDX, RAX, and the divisor operand make up the 3 inputs.
So this will end up performing the division: n1:n0 / d where n1:n0 is a quantity loaded into rdx:rax.
As you correctly observe the div family works on the fixed registers a and d, rax and rdx for divq. The a register gets its input from n0 which is aliased to the 0th register, namely a. n1 is a dummy input aliased to d, probably just to ensure that this register is not used for other purposes.

Resources