I've built a short program written on C and inline assembly on my linux x86_64. It is supposed to write a string to stdout. I found it in an article on the internet:
int write_call( int fd, const char * str, int len ){
long __res;
__asm__ volatile ( "int $0x80":
"=a" (__res):"0"(__NR_write),"b"((long)(fd)),"c"((long)(str)),"d"((long)(len)) );
return (int) __res;
}
void do_write( void ){
char * str = "Paragon output string.\n";
int len = strlen( str ), n;
printf( "string for write length = %d\n", len );
n = write_call( 1, str, len );
printf( "write return : %d\n", n );
}
int main( int argc, char * argv[] ){
do_write();
return EXIT_SUCCESS;
}
But as I run it, it works incorrectly, making output
"write return : -14"
If I build and run it on 32-bit linux it does what is expected.
After some research I fount out that instruction "int $0x80" is a x86 instruction and truncates arguments in registers if called on x86_64.
But I couldn't find a proper substitution of "int $0x80" for x86_64 architecture. I have zero experience in assembly.
What should I put instead of "int $0x80" to receive expected result?
For amd64, you need to use "syscall" - and use different registers - instead of "int 0x80":
http://cs.lmu.edu/~ray/notes/linuxsyscalls/
http://blog.rchapman.org/post/36801038863/linux-system-call-table-for-x86-64
http://crypto.stanford.edu/~blynn/rop/
Here's a good example:
How to invoke a system call via sysenter in inline assembly (x86/amd64 linux)?
#include <unistd.h>
int main(void)
{
const char hello[] = "Hello World!\n";
const size_t hello_size = sizeof(hello);
ssize_t ret;
asm volatile
(
"movl $1, %%eax\n\t"
"movl $1, %%edi\n\t"
"movq %1, %%rsi\n\t"
"movl %2, %%edx\n\t"
"syscall"
: "=a"(ret)
: "g"(hello), "g"(hello_size)
: "%rdi", "%rsi", "%rdx", "%rcx", "%r11"
);
return 0;
Related
I tried to use inline assembly to call the function with three arguments, but it fails with Segmentation fault.
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <assert.h>
#include <stdlib.h>
void callee_test3(char* dest, char* src, size_t srclen)
{
printf("%s %s %li\n", dest, src, srclen);
};
int main()
{
char* dest = "test";
char* src = "src";
size_t srclen = 4;
asm(
"movq %[arg1], %%rdi\n\t"
"movq %[arg2], %%rsi\n\t"
"movq %[arg3], %%rdx\n\t"
"call *%[callee]"
:
:[arg1]"r"((u_int64_t)(dest)),
[arg2]"r"((u_int64_t)(src)),
[arg3]"r"((u_int64_t)(srclen)),
[callee]"r"(callee_test3)
:"cc"
);
return 0;
}
I can call a function with two arguments, but when I added into three arguments, it just failed. Tried to use gdb to trace where the code break it shows :
Breakpoint 1, main () at test.c:24
24 char* dest = "test";
(gdb) next
25 char* src = "src";
(gdb)
26 size_t srclen = 4;
(gdb)
34 :[arg1]"r"((u_int64_t)(dest)),
(gdb)
35 [arg2]"r"((u_int64_t)(src)),
(gdb)
28 asm(
(gdb)
Program received signal SIGSEGV, Segmentation fault.
0x0000555555554872 in ?? ()
For some reasons, the third argument didn't store into the register. My assumption is I'm calling the wrong register to store the third argument. But I couldn't find the resource about that.
I'm writing a C program with inline assembly function that compares two strings if they are same.
When I compile it with 'arm-none-linux-gneabi-gcc' and 'arm-linux-gnueabi-gcc', the results are different. The difference seems to come from keyword 'none' which is place for [vendor] according to google search.
My questions are
Is this the cause of the difference in the results?
If so, what is set as [vendor] in 'arm-linux-gnueabi-gcc'?
My code :
#include <stdio.h>
int * intoneplus(int * i);
char * charoneplus(char * c);
int my_strcmp(const char *src1, const char *src2);
int main(void)
{
const char *a = "Hello world!";
const char *a1 = "Hello world!";
const char *a2 = "hello aorld!";
if(my_strcmp(a, a1)==0)
printf("a and a1 are same sentence\n");
else
printf("a and a1 are different\n");
if(my_strcmp(a, a2)==0)
printf("a and a2 are same sentence\n");
else
printf("a and a2 are different\n");
return 0;
}
int my_strcmp(const char *src1, const char *src2)
{
int ch1, ch2, ret=0;
__asm__ (
"loop:\n\t"
"LDRB %[ch1], [%[src1]], #1 \n\t LDRB %[ch2], [%[src2]], #1\n\t"
"CMP %[ch1], %[ch2]\n\t"
"MOVNE %[ret], #1\n\t BNE done \n\t"
"CMP %[ch1], #0\n\t BNE loop\n\t"
"done:\n\t"
:[ret]"=r"(ret)
:[src1]"r"(src1),[src2]"r"(src2),[ch1]"r"(ch1),[ch2]"r"(ch2)
);
return ret;
}
Compilation and execution results :
#ubuntu:~/test$ arm-linux-gnueabi-gcc -o practice2.out practice2.c -static
#ubuntu:~/test$ qemu-arm practice2.out
464281
a and a1 are different
1
a and a2 are different
#ubuntu:~/test$ arm-none-linux-gnueabi-gcc -o practice2.out practice2.c -static
#ubuntu:~/test$ qemu-arm practice2.out
0
a and a1 are same sentence
1
a and a2 are different
Is there any way in GCC to represent inline __asm__ as char[] array? I want to have something like:
void my_func();
char my_code[] = {
__asm__("callq %0" :: "r" (my_func))
};
Later my_code will be used as run-time patch, i.e.
void another_function();
mprotect(another_function, getpagesize(), PROT_WRITE | PROT_READ | PROT_EXEC);
memcpy(another_function + offset, my_code, sizeof(my_code));
Any ideas?
You can just define a function, compile it, then get it's source machine code?
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
void my_func(void) {}
extern void my_code(void);
extern void my_code_end(void);
__attribute__((__used__)) static void _my_code(void) {
asm volatile(
".globl my_code\n"
"my_code:\n"
" callq *%0\n"
" nop\n"
" ret\n"
".globl my_code_end\n"
"my_code_end:\n"
:: "r" (my_func)
);
}
int main() {
size_t my_code_len = (uintptr_t)my_code_end - (uintptr_t)my_code;
const unsigned char *arr = (const char*)my_code;
printf("my_code[%zu]=", my_code_len);
for (size_t i = 0; i < my_code_len; ++i) {
printf("%02x", arr[i]);
}
printf("\n");
return 0;
}
Example output:
my_code[4]=ffd090c3
We can check it's ok from the assembly output:
$ objdump -D ./a.out
...
0000000000000727 <my_code>:
727: ff d0 callq *%rax
729: 90 nop
72a: c3 retq
...
I'm trying to print a simple hello world string to the console in inline assembly. My assembly (below) works perfectly fine. I tried translating it into GAS as best as possible but putting the variables into the registers through extended assembly proved rather difficult. From what I can tell, the printmsg function doesn't actually do/print anything.
Assembly:
section .text
global _start
_start:
; Write string to stdout
mov eax, 4
mov ebx, 1
mov ecx, string
mov edx, strlen
int 0x80
; Exit
mov eax, 1
mov ebx, 0
int 0x80
section .data
string db 'Hello, World!',10
strlen equ $ - string
C:
#include <stdio.h>
#include <string.h>
void printmsg(char *msg, int len){
asm( "movl $4, %eax;"
"movl $1, %ebx;"
);
asm( "movl %1, %%ecx;"
"movl %1, %%edx;"
:
: "c" (msg), "d" (len)
);
asm("int $0x80");
}
int main(){
char *msg = "Hello, world!";
int len = strlen(msg);
printf("Len is %d\n*msg is %s\n", len, msg);
/* Print msg */
printmsg(msg, len);
/* Exit */
asm( "movl $1,%eax;"
"xorl %ebx,%ebx;"
"int $0x80"
);
}
Using Michael's extended assembly example:
#include <stdio.h>
#include <string.h>
void printmsg(char *string, int length){
asm( "int $0x80\n\t"
:
:"a"(4), "b"(1), "c"(string), "d"(length)
);
}
int main(){
char *string = "Hello, world!\n";
int variable = strlen(string);
/* Print msg */
printmsg(string, variable);
/* Exit */
asm( "movl $1,%eax;"
"xorl %ebx,%ebx;"
"int $0x80"
);
}
I have a rather big project in Linux kernel (h.w).
part of needs to use the copy_to_user function,
for some reason, no matter what is the buffer size it will alyways return the buffer size (and not 0).
can you please help?
here is part of my code:
asmlinkage int sys_receive_mpi_message(int rank, char *message, ssize_t message_size)
{
int reader_rank =-10;
struct task_struct* p = NULL;
struct my_message_list* tmp;
struct list_head *pos, *q;
struct blabla* tmp1;
int bufSize = 0;
int res =0;
int i=0;
if ((rank < 0) || (rank > counter))
{
return -ESRCH;
}
list_for_each(pos, &(my_api_list->list))
{
tmp1 = list_entry(pos, struct blabla, list);
if (tmp1->pid == (current->pid))
{
reader_rank = tmp1->place;
p = tmp1->task_struct_p;
break;
}
}
if (reader_rank == -10)
{
return -ESRCH;
}
list_for_each_safe(pos,q, &(p->message_list->list))
{
tmp=list_entry(pos, struct my_message_list, list);
if (tmp->sender_rank == rank)
{
if (message_size > (tmp->meesage_size))
{
bufSize = tmp->meesage_size;
}
else
{
bufSize = message_size;
}
res = copy_to_user(message,tmp->message,bufSize);
if(res != 0)
{
return -EFAULT;
}
kfree(tmp->message);
list_del(pos);
kfree(tmp);
return (bufSize);
}
return -EFAULT;
}
return -EFAULT;
}
also, I have this struct :
struct my_message_list{
char* message;
int meesage_size;
int sender_rank;
struct list_head list;
};
Update- I foundout that the message I'm geting from the user points to 0 all the time!
does this tells me that the problem is in the wrapper function?
here is my rapper function(the relevent part):
#include <errno.h>
int receive_mpi_message(int rank, char* message, int message_size)
{
int res;
__asm__
(
"pushl %%eax;"
"pushl %%ebx;"
"pushl %%ecx;"
"pushl %%edx;"
"movl $245, %%eax;"
"movl %1, %%ebx;"
"int $0x80;"
"movl %%eax,%0;"
"popl %%edx;"
"popl %%ecx;"
"popl %%ebx;"
"popl %%eax;"
: "=m" (res)
:"m"(rank),"m"(message),"m"(message_size)
);
if (res >= (unsigned long)(-125))
{
errno = -res;
res = -1;
}
return (int) res;
}
What user-space interface do you use for communication? Regardless what user space interface you use (chardev, ioctl, ...), the signature of the function definitions where you hook in should have a __user attribute.
eg: fs.h
struct file_operations {
...
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
...
}
So the char *message variable should be char __user *message, just take a look at the user space interface you use.
Another thing could be that you are calling the method in the wrong place. As far is i know, the copy_*_user functions are only allowed on invocation from the user space. Please someone correct me if i am wrong.
Somehow the date you want to copy could not be copied, as for example, you cannot read the source or write to destination. It is explained at arch/x86/lib/usercopy_32.c:
/*
* Returns number of bytes that could not be copied.
* On success, this will be zero.
*/
I had a problem with my rapper function,
forogot to store data to all the registers:
int receive_mpi_message(int rank, char* message, int message_size)
{
int res;
__asm__
(
"pushl %%eax;"
"pushl %%ebx;"
"pushl %%ecx;"
"pushl %%edx;"
"movl $245, %%eax;"
"movl %1, %%ebx;"
"movl %2, %%ecx;"
"movl %3, %%edx;"
"int $0x80;"
"movl %%eax,%0;"
"popl %%edx;"
"popl %%ecx;"
"popl %%ebx;"
"popl %%eax;"
: "=m" (res)
:"m"(rank),"m"(message),"m"(message_size)
);
if (res >= (unsigned long)(-125))
{
errno = -res;
res = -1;
}
return (int) res;
}