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
Related
I was wondering how I would access or change parts of a string through an array of pointers. This is for a program that plays backgammon. That array of pointers points to over 24 different arrays. here is a sample of the code. I want to be able to know how many of each character there is in each 'r#' string. I need to be able to update each string as players move across the board.
char r1[] = {'R','R','|','|','|','\0'};
char r2[] = {'|','|','|','|','|','\0'};
char r3[] = {'|','|','|','|','|','\0'};
char *a[24] = {r1, r2, r3, r4, ... , r24};
minimal reproducible example
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main() {
char r1[] = {"RR|||"};
char r2[] = {"|||||"};
char r3[] = {"WWWWW"};
char r4[] = {"|||||"};
char r5[] = {"WWW||"};
const char * a[5] = { r1, r2, r3, r4, r5 };
int to;
for(int i=0; i<10; i++){
printf("enter number here: ");
scanf("%d", &to);
char *to_check = strchr(a[to-1], '|');
if(to_check){
printf("successful \n");
}else{
printf("unsuccessful \n");
}
}
return 0;
}
here's the Code:
#include <stdio.h>
#include <string.h>
int main()
{
char C1[6] = "Hello";
char* C2 = C1;
char C21 = C1[1];
printf("\n\nC2 in String : %s\n", C2+1 );
printf("\n\nC2 address : %d\n", C2+1);
printf("\n example de C2+1 : %s", C21);
}
and here's the output
C2 in String : ello
C2 address : 6422273
Segmentation fault
You declared C21 as a char not char pointer. Either change the declaration to:
char * C21 = &C1[1];
or else change %s to %c in the third printf.
If you turn warnings on the compiler will give you a message that lets you work this out for yourself. All -Wall to your command line if you are using gcc.
I use scandir with alphasort. But I need to sort by name between two separator.
Alphasort sorting like this, because of first date string:
FILENAME_000_XXX_20200702133000_20200702183000_000_2000.tar.gz
FILENAME_000_XXX_20200702143000_20200702153000_000_2000.tar.gz
FILENAME_000_XXX_20200702153000_20200702133000_000_2000.tar.gz
FILENAME_000_XXX_20200702163000_20200702143000_000_2000.tar.gz
I need to sort with second date like this:
FILENAME_000_XXX_20200702153000_**20200702133000**_000_2000.tar.gz
FILENAME_000_XXX_20200702163000_**20200702143000**_000_2000.tar.gz
FILENAME_000_XXX_20200702143000_**20200702153000**_000_2000.tar.gz
FILENAME_000_XXX_20200702133000_**20200702183000**_000_2000.tar.gz
I can do with ls/sort command like this:
ls /dir/*.tar.gz | sort -k5,5 -t '_'
How can I do that with C?
Here an example where I use qsort, in the function comparing the strings I bypass the 32 first characters because you want to compare without considering them :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int compare(const void * a, const void * b)
{
/* compare strings bypassing the 32 first characters */
return strcoll(*((char **) a) + 32, *((char **) b) + 32);
}
int main()
{
const char * v[] = {
"FILENAME_000_XXX_20200702133000_20200702183000_000_2000.tar.gz",
"FILENAME_000_XXX_20200702143000_20200702153000_000_2000.tar.gz",
"FILENAME_000_XXX_20200702153000_20200702133000_000_2000.tar.gz",
"FILENAME_000_XXX_20200702163000_20200702143000_000_2000.tar.gz"
};
qsort(v, 4, sizeof(char *), compare);
for (int i = 0; i != 4; ++i)
puts(v[i]);
return 0;
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc -Wall c.c
pi#raspberrypi:/tmp $ ./a.out
FILENAME_000_XXX_20200702153000_20200702133000_000_2000.tar.gz
FILENAME_000_XXX_20200702163000_20200702143000_000_2000.tar.gz
FILENAME_000_XXX_20200702143000_20200702153000_000_2000.tar.gz
FILENAME_000_XXX_20200702133000_20200702183000_000_2000.tar.gz
pi#raspberrypi:/tmp $
Note I do not compare the strings between the two separators but after the first because that does not really change the result.
I also suppose the separator is at the index 31, if this is not the case just use strchr to find the fourth '_' rather than to add 32.
Using that principle you can do :
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
int filter(const struct dirent * d)
{
/* may be check also this is a file */
return !strncmp(d->d_name, "FILENAME_", 9) &&
(strlen(d->d_name) > 32);
}
int compare(const struct dirent ** a, const struct dirent ** b)
{
return -strcoll((*a)->d_name + 32, (*b)->d_name + 32);
}
int main()
{
struct dirent **namelist;
int n = scandir(".", &namelist, filter, compare);
if (n == -1) {
perror("scandir");
return 0;
}
while (n--) {
puts(namelist[n]->d_name);
free(namelist[n]);
}
free(namelist);
return 0;
}
Compilation and execution :
pi#raspberrypi:/tmp $ touch FILENAME_000_XXX_20200702133000_20200702183000_000_2000.tar.gz FILENAME_000_XXX_20200702143000_20200702153000_000_2000.tar.gz FILENAME_000_XXX_20200702153000_20200702133000_000_2000.tar.gz FILENAME_000_XXX_20200702163000_20200702143000_000_2000.tar.gz
pi#raspberrypi:/tmp $ gcc -Wall c.c
pi#raspberrypi:/tmp $ ./a.out
FILENAME_000_XXX_20200702153000_20200702133000_000_2000.tar.gz
FILENAME_000_XXX_20200702163000_20200702143000_000_2000.tar.gz
FILENAME_000_XXX_20200702143000_20200702153000_000_2000.tar.gz
FILENAME_000_XXX_20200702133000_20200702183000_000_2000.tar.gz
pi#raspberrypi:/tmp $
sort -k5,5 -t '_'
A tedious improvement to the other great answer by #bruno would be to find the 5th field separated by _ character in the string and compare only it.
// finds 5th field separated by _ in field and saves length in length
const char *find_5th_arg(const char *str, size_t *length) {
for (int i=0;i<4;++i) {
str = strchr(str, '_');
if (!str) return NULL;
++str;
}
const char *end = strchr(str, '_');
if (!end) end = str + strlen(str);
*length = end - str;
return str;
}
// function to be passed to qsort
int compare_5_5__(const void * a, const void * b) {
const char *x = *(const char **)a;
const char *y = *(const char **)b;
// extract 5th fields
size_t x_5th_len;
const char *x_5th = find_5th_arg(x, &x_5th_len);
size_t y_5th_len;
const char *y_5th = find_5th_arg(y, &y_5th_len);
// printf("%.*s %.*s\n", x_5th_len, x_5th, y_5th_len, y_5th);
// if both input files have 5th
if (x_5th && y_5th) {
// get the shortest
size_t lenmin = x_5th_len > y_5th_len ? y_5th_len : x_5th_len;
int ret = memcmp(x_5th, y_5th, lenmin);
if (ret) return ret;
// if length differ, put the shortest in front
if (x_5th_len > y_5th_len) return 1;
if (x_5th_len < y_5th_len) return -1;
}
// fallback to compare lexicaligraphi-something-ly the whole line
return strcmp(x, y);
}
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'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;