Crash on kfree call (inside a kernel module) - c

I have this code
int64_t ret;
char *fmt = "\n\n\n%s\n\n\n";
char *s;
s = kmalloc(13, GFP_KERNEL);
memcpy(s, "Hello world!\0", 13);
__asm__ __volatile__ (
"movq %2, %%rdi;"
"movq %1, %%rsi;"
"movq $2, %%rax;"
"call printk;"
"movq %%rax, %0;"
: "=r" (ret)
: "r" (s), "r" (fmt)
:
);
__asm__ __volatile__ (
"movq %0, %%rdi;"
"movq $1, %%rax;"
"call kfree;"
:
: "r" (s)
:
);
return ret;
which crashes on the kfree call. It must be something silly, but I can't find out what it is. What is the problem?
EDIT: "Crashes" == The kernel module triggers an Oops.
EDIT: It seems to work just fine if I use m instead of r. But why?

You should look at the generated assembly code (use -S option to gcc) to see exactly what is happening.
I am guessing that the problem is that you didn't specify the correct clobbers for the printk block. Remember that certain registers may be freely used by a called function. The compiler doesn't process the contents of the inline asm block, so it doesn't know it has a call inside. It expects that registers not specified as output or clobber will come out unchanged from the asm block. Thus, I assume the compiler caches the variable s in a register that is destroyed by the printk or your use of rax, rdi and rsi which you also don't tell the compiler. Note that there are specific register constraints, so you could use those instead of moving the arguments around in assembly.
Also note that rax (actually al) is only used for varargs and stdargs functions, and even then it should just contain the number of arguments passed via sse vector (xmm) registers, not the total number. See the x86-64 ABI docs for more information.
Finally, if you really want to write asm code, you should consider writing standalone asm module instead of C if possible. You could save yourself some headache. See this question for an example.

Related

How to use a variable declared in C within inline assembly

I am trying to figure out how to use the variable ret within the inline assembly code below, but I keep getting this error: undefined reference to 'ret.
char getkey(void){
int ret;
asm(
"movq $0, %RAX\n\t"
"INT $0X16\n\t"
"movq %RAX, ret"
);
return ret;
}
What you're trying to do won't work. PC BIOS interrupts, like int 16h, are only available when the system is running in real mode (i.e, at startup before the MMU is enabled); they cannot be used in Linux executables.
That being said, in general, you can specify an output register using gcc assembler constraints. For example:
asm(
"movq $0, %RAX\n"
"int $0x16\n"
: "=a" (ret)
);
Note that there's no mov instruction at the end of this code! The "=A" constraint tells the compiler that the result will be left in the A register; it'll figure out what to do from there. (There are ways to eliminate the first mov as well, if you're clever about it.)

gcc inline assembly error "operand type mismatch for mov"

//quick inline asm statements performing the swap_byte for key_scheduling
inline void swap_byte(unsigned char *x, unsigned char *y)
{
unsigned char t;
asm("movl %1, %%eax;"
"movl %%eax, %0;"
:"=r"(t)
:"r"(*x)
:"%eax");
asm("movl %1, %%eax;"
"movl %%eax, %0;"
:"=r"(*x)
:"r"(*y)
:"%eax");
asm("movl %1, %%eax;"
"movl %%eax, %0;"
:"=r"(*y)
:"r"(t)
:"%eax");
}
Here I am trying to swap the char from x and store in y, and the same for y to x.
I have compiled these instructions by changing movl to mov but with no success. Where is the problem in compiling/linking?
Here is the output from compiling in cygwin:
$ gcc rc4_main.c -o rc4ex
/tmp/ccy0wo6H.s: Assembler messages:
/tmp/ccy0wo6H.s:18: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:18: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:26: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:26: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:34: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:34: Error: operand type mismatch for `mov'
To simplify it even more (than user35443):
asm("" : "=r" (*x), "=r" (*y) : "1" (*x), "0" (*y));
Look ma! No code! And yes, this really works.
To explain how this works:
When the compiler is building the code, it keeps track of what value is in each register. So if had these for inputs to asm:
"r" (*x), "r" (*y)
The compiler will pick a register and put *x in it, then pick a register and put *y in it, then call your asm. But it also keeps track of what variable is in which register. If there were just some way to tell the compiler that all it had to do was start treating the two registers as the opposite variables, then we'd be set. And that's what this code does:
Saying "=r" (*x) means that we are going to be overwriting the value in *x, that that we will be putting the value into a register.
Saying "0" (*y) means that on input to the asm, the compiler must put the value of *y into the same register as is being used by output parameter #0.
So, without using any actually assembly instructions, we have told the compiler to swap these two values.
We don't get this quite "for free" since the compiler must load the values into registers before calling the asm. But since that has to happen anyway...
What about actually updating memory? The compiler will (if necessary) write these values from the registers back to memory. And since it knows what variable is in which register, all works as expected.
unsigned char t;
asm("movl %1, %%eax;"
"movl %%eax, %0;"
:"=r"(t) /* <--here */
:"r"(*x) /* <-- and here */
:"%eax");
You can not move a value from a 32-bit register to a single-byte memory location. t is on the stack and x is somewhere else, but both are accessed in the same way. Problems on the other lines are similar. You should move only a byte.
Try something like this, but there are more ways to do it (I haven't tried that, read below):
unsigned char t;
asm("movb %1, %%al\n"
"movb %%al, %0\n"
:"=r"(t)
:"r"(*x)
:"%al");
asm("movb %1, %%al\n"
"movb %%al, %0\n"
:"=r"(*x)
:"r"(*y)
:"%al");
asm("movb %1, %%al\n"
"movb %%al, %0\n"
:"=r"(*y)
:"r"(t)
:"%al");
The whole procedure can be simplified into this:
asm("movb (%1), %%al\n"
"movb (%2), %%ah\n"
"movb %%ah, (%1)\n"
"movb %%al, (%2)\n"
: /* no outputs for compiler to know about */
: "r" (x), "r" (y)
: "%ax", "memory");
line
movl %%eax, %0;
is full nonsence! So you try to change 0 constant by %eax register It's impossible. In fortran many years ago It was. After that all programs will behave quite unpredictable. Since to avoid that was introduce the rule that any identificatot can't begin with number. But You try do it. It's well to get error. You maybe mean another
movl %0, %%eax;
to set zerro to eax. So better do another code
xorl %%eax, %%eax;
is much better!

asm__volatile() in Linux Kernel

can somebody please explain what exactly this function is doing, I tried to google it, but found nothing:
long __res; //some variable
__asm__ volatile (
"movl $244, %%eax;"
"movl %1, %%ebx;"
"movl %2, %%ecx;"
"movl %3, %%edx;"
"int $0x80;"
"movl %%eax,%0"
: "=m" (__res) //from here can't understand
: "m" (a), "m" (b) , "m" (c)
: "%eax","%ebx","%ecx", "%edx",
);
thanks in advance for any explanation
Taking this step by step:
long __res; //some variable
__asm__ volatile (
"movl $244, %%eax;"
... system calls for 32-bit x86 Linux are selected by the value in %eax. This is the number of the get_thread_area syscall. See arch/x86/include/asm/unistd_32.h (in recent kernels at least) for the list of syscall numbers. (Note: syscall numbers are not the same between 32-bit and 64-bit.)
"movl %1, %%ebx;"
"movl %2, %%ecx;"
"movl %3, %%edx;"
... parameters to system calls are passed in registers. For 32-bit x86, up to five parameters are passed in registers, in the order %ebx, %ecx, %edx, %esi, %edi (the 6th argument, for the few syscalls that need it, is passed on the user stack). %1, %2, %3 refer to the 2nd, 3rd and 4th items mentioned in the "constraints" for the inline assembler (see below).
(This seems slightly odd, by the way: the get_thread_area syscall only needs one argument...)
"int $0x80;"
... invokes the syscall.
"movl %%eax,%0"
... syscalls return a result in %eax; the %0 refers to the first item mentioned in the constraints.
: "=m" (__res) //from here can't understand
... "constraints" tell gcc where it can put the input and output values that are used and produced by the inline assembler block. This first section (after the first :) is for outputs. "=m" here says that __res should be held in memory ("m") and that it is write-only, i.e. any previous value will be overwritten ("="). Operands in constraints can be referred to by numbers in the inline assembly block (e.g. %0), starting from 0 for the first to appear.
: "m" (a), "m" (b) , "m" (c)
... this next section is for inputs. This says that they will all be placed in memory.
: "%eax","%ebx","%ecx", "%edx",
... this final section indicates "clobbered" registers, i.e. those that will be overwritten as a result of code inside the inline assembler block. GCC will put the inline assembler block into the middle of other code that it generates, but it doesn't know what the instructions inside the block actually do - so you have to tell it that any values that may have been in those registers before the block will no longer be valid afterwards.
);
That function is performing a syscall (due to the x86 int 0x80).
The part you flagged is the GCC inline assembler helpers - which allows GCC to change the placeholders (%0-%3) to actual values as given by a C name, in this case, __res, a, b, c.
You can read about the exact inline assembler syntax here:
http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
You can find all the info you need about the gcc inline assembly syntax here:
http://www.ibm.com/developerworks/linux/library/l-ia.html

Writing a Linux int 80h system-call wrapper in GNU C inline assembly [duplicate]

This question already has answers here:
How to invoke a system call via syscall or sysenter in inline assembly?
(2 answers)
Closed 3 years ago.
I'm trying to use inline assembly...
I read this page http://www.codeproject.com/KB/cpp/edujini_inline_asm.aspx but I can't understand the parameters passing to my function.
I'm writing a C write example.. this is my function header:
write2(char *str, int len){
}
And this is my assembly code:
global write2
write2:
push ebp
mov ebp, esp
mov eax, 4 ;sys_write
mov ebx, 1 ;stdout
mov ecx, [ebp+8] ;string pointer
mov edx, [ebp+12] ;string size
int 0x80 ;syscall
leave
ret
What do I have to do pass that code to the C function... I'm doing something like this:
write2(char *str, int len){
asm ( "movl 4, %%eax;"
"movl 1, %%ebx;"
"mov %1, %%ecx;"
//"mov %2, %%edx;"
"int 0x80;"
:
: "a" (str), "b" (len)
);
}
That's because I don't have an output variable, so how do I handle that?
Also, with this code:
global main
main:
mov ebx, 5866 ;PID
mov ecx, 9 ;SIGKILL
mov eax, 37 ;sys_kill
int 0x80 ;interruption
ret
How can I put that code inline in my code.. so I can ask for the pid to the user.. like this..
This is my precode
void killp(int pid){
asm ( "mov %1, %%ebx;"
"mov 9, %%ecx;"
"mov 37, %%eax;"
:
: "a" (pid) /* optional */
);
}
Well, you don't say specifically, but by your post, it appears like you're using gcc and its inline asm with constraints syntax (other C compilers have very different inline syntax). That said, you probably need to use AT&T assembler syntax rather than Intel, as that's what gets used with gcc.
So with the above said, lets look at your write2 function. First, you don't want to create a stack frame, as gcc will create one, so if you create one in the asm code, you'll end up with two frames, and things will probably get very confused. Second, since gcc is laying out the stack frame, you can't access vars with "[ebp + offset]" as you don't know how it's being laid out.
That's what the constraints are for -- you say what kind of place you want gcc to put the value (any register, memory, specific register) and the use "%X" in the asm code. Finally, if you use explicit registers in the asm code, you need to list them in the 3rd section (after the input constraints) so gcc knows you are using them. Otherwise it might put some important value in one of those registers, and you'd clobber that value.
You also need to tell the compiler that inline asm will or might read from or write to memory pointed-to by the input operands; that is not implied.
So with all that, your write2 function looks like:
void write2(char *str, int len) {
__asm__ volatile (
"movl $4, %%eax;" // SYS_write
"movl $1, %%ebx;" // file descriptor = stdout_fd
"movl %0, %%ecx;"
"movl %1, %%edx;"
"int $0x80"
:: "g" (str), "g" (len) // input values we MOV from
: "eax", "ebx", "ecx", "edx", // registers we destroy
"memory" // memory has to be in sync so we can read it
);
}
Note the AT&T syntax -- src, dest rather than dest, src and % before the register name.
Now this will work, but its inefficient as it will contain lots of extra movs. In general, you should NEVER use mov instructions or explicit registers in asm code, as you're much better off using constraints to say where you want things and let the compiler ensure that they're there. That way, the optimizer can probably get rid of most of the movs, particularly if it inlines the function (which it will do if you specify -O3). Conveniently, the i386 machine model has constraints for specific registers, so you can instead do:
void write2(char *str, int len) {
__asm__ volatile (
"movl $4, %%eax;"
"movl $1, %%ebx;"
"int $0x80"
:: "c" (str), /* c constraint tells the compiler to put str in ecx */
"d" (len) /* d constraint tells the compiler to put len in edx */
: "eax", "ebx", "memory");
}
or even better
// UNSAFE: destroys EAX (with return value) without telling the compiler
void write2(char *str, int len) {
__asm__ volatile ("int $0x80"
:: "a" (4), "b" (1), "c" (str), "d" (len)
: "memory");
}
Note also the use of volatile which is needed to tell the compiler that this can't be eliminated as dead even though its outputs (of which there are none) are not used. (asm with no output operands is already implicitly volatile, but making it explicit doesn't hurt when the real purpose isn't to calculate something; it's for a side effect like a system call.)
edit
One final note -- this function is doing a write system call, which does return a value in eax -- either the number of bytes written or an error code. So you can get that with an output constraint:
int write2(const char *str, int len) {
__asm__ volatile ("int $0x80"
: "=a" (len)
: "a" (4), "b" (1), "c" (str), "d" (len),
"m"( *(const char (*)[])str ) // "dummy" input instead of memory clobber
);
return len;
}
All system calls return in EAX. Values from -4095 to -1 (inclusive) are negative errno codes, other values are non-errors. (This applies globally to all Linux system calls).
If you're writing a generic system-call wrapper, you probably need a "memory" clobber because different system calls have different pointer operands, and might be inputs or outputs. See https://godbolt.org/z/GOXBue for an example that breaks if you leave it out, and this answer for more details about dummy memory inputs/outputs.
With this output operand, you need the explicit volatile -- exactly one write system call per time the asm statement "runs" in the source. Otherwise the compiler is allowed to assume that it exists only to compute its return value, and can eliminate repeated calls with the same input instead of writing multiple lines. (Or remove it entirely if you didn't check the return value.)

C inline assembly memory copy

I am trying to write some inline assembly into C. I have two arrays as input, what I need is to copy one element in array1 into array2, and the following is what I have at the moment:
asm (
"movl %0,%%eax;"
"movl %1,%%ebx;"
"movl (%%eax),%%ecx;"
"movl %%ecx,(%ebx);"
"xor %%ecx,%%ecx;"
"movl 4(%%eax),%%ecx;"
//do something on %ecx
"movl %%ecx,4(%ebx);" //write second
:
:"a"(array1),"b"(array2)
);
Why do I get a segmentation fault?
Your inline assembler code is broken. You can't directly use EAX and EBX without adding them to the clobber list. Otherwise the compiler does not know which registers have been modified.
It is very likely that one of the registers that you've modified contained something damn important that later caused the segmentation fault.
This code will copy one element from array1 to array2:
asm (
"movl (%0), %%eax \n\t" /* read first dword from array1 into eax */
"movl %%eax, (%1) \n\t" /* write dword into array2
: /* outputs */
: /* inputs */ "r"(array1),"r"(array2)
: /* clobber */ "eax", "memory"
);
A better version with proper register constraints would drop the hard coded EAX like this:
int dummy;
asm (
"movl (%1), %0 \n\t"
"movl %0, (%2) \n\t"
: /* outputs, temps.. */ "=r" (dummy)
: /* inputs */ "r"(array1),"r"(array2)
: /* clobber */ "memory"
);
Btw - In general I have the feeling that you're not that familiar with assembler yet. Writing inline-assembler is a bit harder to get right due to all the compiler magic. I suggest that you start writing some simple functions in assembler and put them into a separate .S file first.. That's much easier..
Your best option is C code:
target_array[target_idx] = source_array[source_idx];
This avoids segmentation faults as long as the indexes are under control.
what about memcpy ?

Resources