What is the colon in the c language between two strings? - gcc

I'm trying to edit the IDT (interrupt Descriptor Table) and I have found this code which should give me access to the structure. But I didn't understand what the colon in the asm line is. I guess that it's some game with bitmaps in C, and this is somehow padding the instruction. But I couldn't find anything definitive.
If it helps, right now the compiler says: invalid 'asm': invalid expression as operand. Still fighting this one... :)
So, what is the colon doing there?

This is the extended asm syntax from gcc compiler. Here's a link describing the syntax:
asm ( assembler template
: output operands /* optional */
: input operands /* optional */
: list of clobbered registers /* optional */
);
and the example:
int a=10, b;
asm ("movl %1, %%eax;
movl %%eax, %0;"
:"=r"(b) /* output */
:"r"(a) /* input */
:"%eax" /* clobbered register */
);
"b" is the output operand, referred to by %0 and "a" is the input
operand, referred to by %1.
"r" is a constraint on the operands. We’ll
see constraints in detail later. For the time being, "r" says to GCC
to use any register for storing the operands. output operand
constraint should have a constraint modifier "=". And this modifier
says that it is the output operand and is write-only.
There are two
%’s prefixed to the register name. This helps GCC to distinguish
between the operands and registers. operands have a single % as
prefix.
The clobbered register %eax after the third colon tells GCC
that the value of %eax is to be modified inside "asm", so GCC won’t
use this register to store any other value.

Related

Inline assembly using insl instruction - passing variables in C to registers

Recently, I read Xv6, a simple Unix-like teaching operating system and its source code. There is one example of inline assembly, which I cannot find answer to my question about the implementation. There is a stackoverflow article How to use ins instruction with GNU assembler, which cannot help answer that either.
The following is the code snippet I have trouble to understand how inline assembly works for insl instruction.
0461 static inline void
0462 insl(int port, void *addr, int cnt)
0463 {
0464 asm volatile("cld; rep insl" :
0465 "=D" (addr), "=c" (cnt) :
0466 "d" (port), "0" (addr), "1" (cnt) :
0467 "memory", "cc");
0468 }
And one calling function looks like this.
8573 insl(0x1F0, dst, SECTSIZE/4);
My understanding about insl instruction in GCC transfers a string (of 4 bytes) from a port specified in the DX register to the memory (of double words) pointed to by the ES:EDI as destination index. And, Use the rep prefix with the insl instruction for a block transfer of CX double words. The questions I have is, not sure how GCC will pass the values of variables port, *addr, and cnt to the registers of DX, EDI, and CX? I tried to find more information in GCC manual, but not. (Please forgive me as a GCC novice. Maybe I did not exhaust all the ways to find it yet.)
I tried to imagine that could be related to line 0466, "d" (port), "0" (addr) and "1" (cnt). If it is true, I still don’t understand why the first argument is listed as "d", and next ones starting from position 0 with "0" (addr) and "1" (cnt). Why not "0" (port), "1" (addr), "2" (cnt)? And any rule of the mapping to registers DX, EDI, and CX?

Analyze store instruction consisting inttoptr in LLVM

I am trying to analyze a byte code consisting of a store instruction with inttoptr. I am having trouble to detect whether a store instruction has the inttoptr value as the value operand (3rd instruction in the following code in entry BB). My opcode looks like the following:
define dso_local i32 #test(i32* %p) #0 {
entry:
%p.addr = alloca i32*, align 8
store i32* %p, i32** %p.addr, align 8
store i32* inttoptr (i64 1000 to i32*), i32** %p.addr, align 8
%0 = load i32*, i32** %p.addr, align 8
%1 = load i32, i32* %0, align 4
ret i32 %1
}
I am trying to analyze the store instruction and trying to find whether inttoptr is in a store instruction by using classof method and with dyn_cast like the following code:
StoreInst *store = dyn_cast<StoreInst>(I);
Value *vv = store->getValueOperand();
Value *vp = store->getPointerOperand();
if(IntToPtrInst::classof(vv)){
outs() << "Inttoptr found\n";
}
if(Instruction *inp = dyn_cast<IntToPtrInst>(vv)){
outs() << "Inttoptr found\n";
}
It seems I am not being able to detect inttoptr with any of the methods. I know the byte code is not creating a separate instruction for the inttoptr but it is merging with the store instruction. It would be really nice if anyone points me what I am missing and how I can detect the inttoptr in a store instruction.
The cast you're interested in is not an instruction, but rather a constant cast from the constant integer 1000 to a pointer. You can detect it using a test like isa<ConstantExpr>(foo->getPointerOperand()) && cast<ConstantExpr>(foo->getPointerOperand())->getOpcode() == ConstantExpr::IntToPtrCast, but I typed that from memory and I'm sure there are typos.
When you read IR, instructions are always on their own line, while constants are inline as arguments or initialisers, even the quite complex constants produced using ConstantExpr.

NEON inline assembly - store query

I am trying to learn how to utilize NEON using gcc and inline assembly.
While it is confusing and slow going, I making some progress (It's been 10 years since I last tried writing assembly).
My simple program loads a (small) vector, saturation sums it, and stores it. The problem I am having is that I cannot seem to store the result in the place I want.
When I use an unused array pointer (r) in my output list, I get an error "impossible constraint in asm". If I then create a second pointer to it (rptr), it assembles, but it re-uses an input register r2 which is a, effectively overwriting the input.
(I know my arrays are 32 elements in size and that I'm only processing one element, I plan to try to loop, or try load more registers for parallel processing next)
void vecSum()
{
//two input arrays of 32 bit types, one output
int32_t a[32];
int32_t b[32];
int32_t r[32];
//initialize
for(int cnt = 0; cnt < 32; cnt++)
{
a[cnt] = 0x33333333;
b[cnt] = 0x11111111;
r[cnt] = 0;
}
void *rptr = r;
__asm__ volatile(
"vld1.32 {d0},[%[ina]]!\n" //load the neon register with our data at a, post increment the reg
"vld1.32 {d1},[%[inb]]!\n"
"vqadd.s32 d0,d1\n" //perform the sat
"vst1.32 d0,[%[result]]\n" //store the answer
: [result]"=r" (rptr) /*r*/
: [ina] "r" (a), [inb] "r" (b)
: /*"d0", "d1", "d2"*/);
for(int g=0; g < 32; g++)
{
printf("0x[%d]%x ",g,a[g]);
}
}
Objdump:
for(int cnt = 0; cnt < 32; cnt++)
780: e3530080 cmp r3, #128 ; 0x80
784: 1afffff7 bne 768 <_Z8vecSum32v+0x28>
"vld1.32 {d1},[%[inb]]!\n"
"vqadd.s32 d0,d1\n" //perform the sat
"vst1.32 d0,[%[result]]\n"
: [result]"=r" (rptr)
: [ina] "r" (a), [inb] "r" (b)
: /*"d0", "d1", "d2"*/);
788: f422078f vld1.32 {d0}, [r2]
78c: f421178d vld1.32 {d1}, [r1]!
790: f2200011 vqadd.s32 d0, d0, d1
794: f402078f vst1.32 {d0}, [r2]
In summary, if I try vst1.32 d0,[%[result]] where result is the array pointer r, I get a compilation error. If I rptr ( another pointer to r) it comiles, but uses r2 (the array a) as the output.
Can anybody explain why I get the error outputting to r? And why the ptr to r is a?
rptr is declared as an output when it should be an input and "memory" is missing from the clobber list.
Alternatively you may put the arrays in structs and use the structs (rather than pointers) as arguments to the asm statement.
Consider if the asm contained add %[result], %[ina], %[inb]. There's no harm whatsoever in allocating r2 for both result and ina there. Since GCC doesn't go analysing the contents of the asm statement, its default assumption is that it contains a single instruction like that, so if yours is more complicated then you need to say so in order for things to work as expected.
Specifically, to prevent the problematic overlapping register allocation here, you need to be honest about the fact that you that your asm modifies the input registers - most simply via the + modifier (which then actually makes them outputs as far as GCC is concerned). Another unpleasant side effect of not doing that, is that the compiler would assume that e.g. r1 still holds the address of b afterwards, and may generate later code relying on that which will then go horribly wrong thanks to what the asm actually did.
Furthermore, you don't modify the result pointer, and only use its value as an input, so saying it's a write-only output operand is very wrong.
As for the issue with r, well, by specifying it as an output operand, you're saying that the asm writes a value back to that variable. Except you can't do that with an array variable in C (<languagelawyer> arrays are not modifiable lvalues) - you need to give the asm a variable which holds the address of the array and can be assigned back to, i.e. a pointer variable. The reason you can use the arrays directly as input operands, is because input operands are expressions, not variables, and an expression that evaluates to an array is automatically converted to a pointer to first element of that array (but is still not an lvalue </languagelawyer>).
All in all then, with appropriate pointer variables for a and b, suitable operands and constraints for this code as-is would look more like this:
: [ina] "+r" (aptr), [inb] "+r" (bptr)
: [result] "r" (r)
: "d0", "d1", "memory" /* getting clobbers right is also important */
Side note: if you just want to get to grips with NEON instructions rather than fighting with GCC, intrinsics are an alternative to consider.

Can pretty variable names be used for registers in GCC inline assembly?

I have some inline assembly. I want GCC to have total freedom in choosing GP registers to allocate. I also want to use pretty names for registers inside the assembly for ease of comprehension for future maintainers. I think I did this previously (10+ years ago) for ARM 5te but am now scratching my head while writing some AArch64 code.
In a simpler example, this is what I want:
uint32_t arg1 = 1, arg2 = 2, result;
asm volatile(
"add %result, %arg1, %arg2\n"
// Outputs:
: ???
// Inputs:
: ???
// Clobbered:
: ???
);
I figure I need the right voodoo to go where I have written "???" above.
Is it possible?
Yes.
[arg1] "r" (arg1)
For example. The two names([arg1] and (arg1) above) can be different.
Inside the assembly code, you'd use:
add %[result], %[arg1], %[arg2]
Documentation link.
Here's your whole example reworked (case changed for the assembly variables just to illustrate that they needn't be the same):
uint32_t arg1 = 1, arg2 = 2, result;
asm volatile(
"add %[RESULT], %[ARG1], %[ARG2]\n"
: [RESULT]"=r"(result) /* output */
: [ARG1]"r"(arg1), [ARG2]"r"(arg2) /* inputs */
: /* no clobbers */
);

what's meaning of f in "js 2f\n\t"?

the codes:
extern inline int strncmp(const char * cs, const char * ct, int count)
{
register int __res;
__asm__("cld\n"
"1:\tdecl %3\n\t"
"js 2f\n\t"
"lodsb\n\t"
"scasb\n\t"
"jne 3f\n\t"
"testb %%al, %%al\n\t"
"jne 1b\n"
"2:\txorl %%eax,%%eax\n\t"
"jmp 4f\n"
"3:\tmovl $1,%%eax\n\t"
"j1 4f\n\t"
"negl %%eax\n"
"4:"
:"=a" (__res):"D" (cs), "S" (ct), "c" (count):"si","di","cx");
return __res;
}
I don't understand the f in "js 2f\n\t" and the b in "jne 1b\n", How to
understand this ? which book I should look? Thank you.
In this context f means forward and b means backward. So js 2f means jump forward to label 2, if sign set.
You'll want to look into gcc inline assembly. I can't seem to find any reference online to include this bit, but I know you can find it in Professional Assembly Language.
Why can't we use named labels ? To quote from the book:
If you have another asm section in your C code, you cannot use the
same labels again, or an error message will result due to duplicate
use of labels.
So what can we do ?
The solution is to use local labels. Both conditional and
unconditional branches allow you to specify a number as a label, along
with a directional flag to indicate which way the processor should
look for the numerical label. The first occurrence of the label found
will be taken.
About modifiers:
Use the f modifier to indicate the label is forward from the jump
instruction. To move backward, you must use the b modifier.
This is documented in the manual for the assembler.

Resources