Puppy Linux Discussion Forum Forum Index Puppy Linux Discussion Forum
Puppy HOME page : puppylinux.com
"THE" alternative forum : puppylinux.info
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

The time now is Wed 01 Oct 2014, 18:18
All times are UTC - 4
 Forum index » Off-Topic Area » Programming
unsorted C macros for small/fast static apps
Post_new_topic   Reply_to_topic View_previous_topic :: View_next_topic
Page 2 of 3 Posts_count   Goto page: Previous 1, 2, 3 Next
Author Message
technosaurus


Joined: 18 May 2008
Posts: 4351

PostPosted: Thu 06 Dec 2012, 00:33    Post_subject:  

just need to figure out how to deal with blah-0041.2 and blah-041.1
_________________
Web Programming - Pet Packaging 100 & 101
Back to top
View user's profile Send_private_message 
Ibidem

Joined: 25 May 2010
Posts: 493
Location: State of Jefferson

PostPosted: Thu 06 Dec 2012, 19:24    Post_subject:  

technosaurus wrote:
just need to figure out how to deal with blah-0041.2 and blah-041.1

If you look in the manpage, that isn't ambiguous: numbers starting with 0 are considered to have an implied decimal point before the first 0, so the more leading zeros, the smaller.
Since it diverges at 00 vs 04, anything after the decimal point is ignored.

But there is another bug in the version I just posted:
compare 2004 204, and my code assumes it's dealing with a leading 0 Embarassed
I have an idea for fixing it, but haven't done so yet.
Back to top
View user's profile Send_private_message 
technosaurus


Joined: 18 May 2008
Posts: 4351

PostPosted: Wed 30 Jan 2013, 03:58    Post_subject:  

simple qsort example, takes all arguments and prints sorted tab separated list
Code:
#include <string.h>

static inline int cmp(const void *a, const void *b){
   return strcmp(*(const char **)a, *(const char **)b);
}

int main(int argc, char *argv[]){
    qsort(++argv, --argc, sizeof(char *), cmp);
    while (argc){
      write(1,argv[0],strlen(argv[0]));
      write(1,(--argc && argv++)?"\t":"\n",1);
   }
}

_________________
Web Programming - Pet Packaging 100 & 101
Back to top
View user's profile Send_private_message 
technosaurus


Joined: 18 May 2008
Posts: 4351

PostPosted: Thu 07 Feb 2013, 00:07    Post_subject:  

a faster (but bigger) strlen -needs work (misses \0 on multiples of Cool

Code:
size_t strlen(char *s){
size_t *v,ret;
v=(size_t  *)s;
while (!(~((((*v & 0x7F7F7F7F) + 0x7F7F7F7F) | *v) | 0x7F7F7F7F))) v++; /*64bit size_t?*/
ret=(char *)v-s;
while (s[++ret]);
return ret;
}


notes: need to use an unsigned int or 0 is 111111111111.....
maybe use:
((*v>>24)&&(*v&0xFF00FFFF))&&((*v&0xFFFF00FF)&&(*v<<24))
because the compiler can combine some of these operations and/or thread them

_________________
Web Programming - Pet Packaging 100 & 101
Back to top
View user's profile Send_private_message 
technosaurus


Joined: 18 May 2008
Posts: 4351

PostPosted: Sat 16 Feb 2013, 18:04    Post_subject:  

here is a one-liner to generate macros for 300+ syscalls
Code:
grep __NR_ unistd_32.h |awk '
{print "#define " substr($2,6,length($2)) "(...) syscall(" $2 ", __VA_ARGS__ )"}
' | sort > syscalls.h

and now you have a 0kb c "library"

Note: zero-arg functions like fork() may need to be modified on older compilers and all of the types (structs, etc...) will need to be defined and there is absolutely no type checking. If you would like some semblance of type checking, you can later modify the defines to be static inline functions like:

Code:
static inline long mycall(int a, char *b, struct somestruct c){
return syscall(__NR_mycall, a, b, c);
}


There are quite a few other functions in the kernel that would be useful if you wanted to wrap them in a syscall for userspace (all of the crypto stuff and filesystem detection for instance)

_________________
Web Programming - Pet Packaging 100 & 101
Back to top
View user's profile Send_private_message 
technosaurus


Joined: 18 May 2008
Posts: 4351

PostPosted: Sun 17 Feb 2013, 23:20    Post_subject:  

still working on syscalls. Here is a wacked out macro that redefines syscall() based on the number of args.
Code:
#define NARGS(...) NARGS_(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0)(__VA_ARGS__)
#define NARGS_(dummy, n1, n2, n3, n4, n5, n6, n, ...) syscall##n
#define syscall(...) NARGS(__VA_ARGS__)

thus syscall(__NR_mycall) becomes syscall0(mycall)
while syscall(__NR_mycall,a,b,c,d,e,f) becomes syscall6(mycall,a,b,c,d,e,f)

... and you thought you needed c++ for this Smile

_________________
Web Programming - Pet Packaging 100 & 101
Back to top
View user's profile Send_private_message 
technosaurus


Joined: 18 May 2008
Posts: 4351

PostPosted: Mon 04 Mar 2013, 01:27    Post_subject:  

here is a good link to some try-catch macros
http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html

_________________
Web Programming - Pet Packaging 100 & 101
Back to top
View user's profile Send_private_message 
technosaurus


Joined: 18 May 2008
Posts: 4351

PostPosted: Sat 27 Jul 2013, 13:14    Post_subject:  

I now have the beginnings of my nano-libc that can be used as a single header file and have added many mime types to the "file --mime-type alternative"

The libc should work with any gcc toolchain and handles all linux syscalls (stat is the only one with the structs predefined though) as well as a couple of string functions and a basic {f}printf - I recommend using musl libc to add any extra functions you may need.

A statically compiled program that uses printf is just over 1kb (other libc implementations are at least 7kb) and just a basic write(1,"hello world\n",12); is ~600b (without using sstrip, - that brings it to under half a kb)

ftype.c has also been tested with it and runs 60-120 times faster than `file --mime-type`
ftype.c.gz
Description 
gz

 Download 
Filename  ftype.c.gz 
Filesize  10.13 KB 
Downloaded  206 Time(s) 
libc.h.gz
Description 
gz

 Download 
Filename  libc.h.gz 
Filesize  5.14 KB 
Downloaded  210 Time(s) 

_________________
Web Programming - Pet Packaging 100 & 101
Back to top
View user's profile Send_private_message 
goingnuts

Joined: 07 Dec 2008
Posts: 780

PostPosted: Mon 29 Jul 2013, 00:18    Post_subject:    

Cool!
Is it possible to use the libc.h directly as #include "libc.h" or is it better to copy the different functions into the main code?
I tried to substitute the codeblock in ftype.c within #ifdef STANDALONE with #include "libc.h" but got some errors compiling:
Code:
libc.h:554: error: `__NR_write' undeclared
ftype.c:910: error: `__NR_stat' undeclared (first use in this function)

Compiling ftype.c unmodified
Code:
 [diet]  gcc -nostdlib -nostdinc -fno-builtin -Os -fno-asynchronous-unwind-tables -fomit-frame-pointer -fdata-sections -ffunction-sections -Wl,--gc-sections,-s ftype.c -o ftype

with diet libc I get errors:
Code:
ftype.c:(.text+0x0): multiple definition of `_start'
/usr/dietlibc/lib-i386/start.o:(.text+0x0): first defined here
/usr/dietlibc/lib-i386/libc.a(atexit.o): In function `exit':
atexit.c:(.text+0x24): multiple definition of `exit'
but with uclibc & glibc no problems.
Back to top
View user's profile Send_private_message Visit_website 
technosaurus


Joined: 18 May 2008
Posts: 4351

PostPosted: Tue 30 Jul 2013, 00:35    Post_subject:  

I leave off nostdinc so that it picks up the NR* syscall defines from the linux headers ... See unistd.h (the only include in libc.h) they could be included directly, but I am leaving platform specific stuff out as much as possible for future arm stuff. My latest version of ftype only uses libc.h instead of builtin standalone code. I think Its currently a good starting point though to bootstrap whatever additional functions you may need for a single purpose app. At least printf doesnt keep your app from running on the stack like most implementations do... at least for now since only the most common bits are implemented (va_* was the hard part, but it can be used for other fxns that need variable# of args)

When you build with the parameters in the libc.h header it should work the same for any toolchain ... Otherwise it is sucking in includes from other than just the linux headers, but I havent found a good way to get 1 without the other.

_________________
Web Programming - Pet Packaging 100 & 101
Back to top
View user's profile Send_private_message 
technosaurus


Joined: 18 May 2008
Posts: 4351

PostPosted: Tue 06 Aug 2013, 21:54    Post_subject:  

Its a bit disorganized but I added a ton of stuff to test
Edit: ok, really disorganized, I will do a bunch of cleanup and testing before the next version and try to complete the string functions and will be in a new thread.

The primary purpose is to allow for smaller overheads in static binaries so that multicall binaries are not needed so much. To finish this out, I need to make a tool chain that symlinks all of the stdinc files to libc.h and wraps cc with nostdlib nostdinc and fnobuiltin and some optimizations.

If anyone uses it and runs into missing structs or defined constants, please post them, (figuring out the basic types used in structs can take a lot of time) which also reminds me, I should define these to the basic types as I find them (rather than typedeffing them) ... Of course that means you should do development against a "real" c library first for sanity checks (any noted differences will help). Currently only targeting x86, but will consider basic arm support (64 bit versions wouldnt make sense, but feel free to fork )

note, linux 3.10 is lts so it will be the basis, thus sycalls may not be available in older kernels... most static binaries will work unless you try to use a newer syscall like finit_module on an older kernel
libc.h-0.1.gz
Description 
gz

 Download 
Filename  libc.h-0.1.gz 
Filesize  12.4 KB 
Downloaded  213 Time(s) 

_________________
Web Programming - Pet Packaging 100 & 101
Back to top
View user's profile Send_private_message 
technosaurus


Joined: 18 May 2008
Posts: 4351

PostPosted: Wed 21 May 2014, 19:14    Post_subject:  

Here is another set of macros for packed/sparse boolean values useful for storing a large array of flags:

Code:
#define getbit(x,n) x[n>>((sizeof(*x)>>1)+3)]  &  1 << (n&((sizeof(*x)<<3)-1))
#define setbit(x,n) x[n>>((sizeof(*x)>>1)+3)] |=  1 << (n&((sizeof(*x)<<3)-1))
#define flpbit(x,n) x[n>>((sizeof(*x)>>1)+3)] ^=  1 << (n&((sizeof(*x)<<3)-1))
#define clrbit(x,n) x[n>>((sizeof(*x)>>1)+3)] &= ~( 1 << (n&((sizeof(*x)<<3)-1)) )

//note the << and >> operations could depend on endianness
// >>3 == /8 and <<3 == *8, but is faster it with optimization off


to initialize a large array of booleans all you need to do is:
char cbits[]={0,0xF,0,0xFF};
// 00000000000011110000000011111111
or for all zeroes
char cbits[4]={0};
// 00000000000000000000000000000000
int ibits[]={0xF0F0F0F0,~0};
//1111000011110000111100001111000011111111111111111111111111111111

then just use the macros to access the bitfields
If you will only be accessing 1 type of array like this it may be better to make the macros into proper functions like:
Code:
char getbit(char *x, unsigned n){
  return x[n>>3]  &  1 << (n&7);
}


Why do this? Normally boolean types take at least 8 bits because they have to be addressable in memory on x86(_64) they are 32 (or 64) bits.

If you have a large amount of flags in the range of thousands, it could be the difference in whether the program stays in cache (or run out of memory on constrained systems)

_________________
Web Programming - Pet Packaging 100 & 101
Back to top
View user's profile Send_private_message 
technosaurus


Joined: 18 May 2008
Posts: 4351

PostPosted: Tue 27 May 2014, 23:42    Post_subject:  

Here is a demo of an array of function pointers that simplifies and expands what most demos will show. The F() macro included should work for most function types

Code:
#include <stdio.h>

int f0(int a, int b){return a+b;} //ADD
int f1(int a, int b){return a-b;} //SUBTRACT
int f2(int a, int b){return a*b;} //MULTIPLY
int f3(int a, int b){return a/b;} //DIVIDE

//use these to access the function in the array
enum{ ADD, SUBTRACT, MULTIPLY, DIVIDE, NUM_FUNCS};

//assign the corresponding functions in same order as enum above
int (*f[NUM_FUNCS]) () = {f0,f1,f2,f3};

//this uses the first arg as the function pointer index and passes the remaining args to it
#define F(x,...) (*f[x]) (__VA_ARGS__)

int main(void){
  printf("%d\n", F(ADD, 50, 6) );
  printf("%d\n", F(SUBTRACT, 50, 6) );
  printf("%d\n", F(MULTIPLY, 50, 6) );
  printf("%d\n", F(DIVIDE, 50, 6) );
  return 0;
}


This is useful for iterating on data with different functions, conditionally calling arbitrary functions, implementing an object based system, or even to save small amount of space in a shared library (enums can be 1 byte vs <long_function_name>)

_________________
Web Programming - Pet Packaging 100 & 101
Back to top
View user's profile Send_private_message 
technosaurus


Joined: 18 May 2008
Posts: 4351

PostPosted: Sun 22 Jun 2014, 20:45    Post_subject:  

This code will load a shared library and pass args to a function it contains. Currently only supports char* types, but can add a parser later
Code:
//gcc -rdynamic -o foo foo.c -ldl
#include <dlfcn.h> /*for dlopen,dlsym,dlclose*/

int main(int argc, char **argv){

   /* get a "handle" for a shared library*/
   void *handle = dlopen(argv[1], RTLD_LAZY);

   /* make sure we got a handle before continuing*/
   if (! handle) return 1;

   /*undefined, but workable solution : POSIX.1-2003 (Technical
       Corrigendum 1) */
   void* (*f)()=dlsym(handle, argv[2]);

   /*now call the function f(argv[3],argv[4],...argv[argc]); */
   //TODO convert args to unsigned char representations for other types
   while (argc > 2)  /*ugh, have to use asm to preserve stack*/
      asm("push %0"::"r"(argv[argc--])); /*from right to left*/
   asm("call *%0"::"r"(f)); //TODO  "=a"(ret) where is uchar[XXX]

   /*remember that shared library we opened?*/
   dlclose(handle);
   return 0;
}


Another helper for seeing if a string end with an extension
Code:
int strhasext(char *s, char *ext){
   return !strcmp(s+strlen(s)-strlen(ext),ext);
}

_________________
Web Programming - Pet Packaging 100 & 101
Back to top
View user's profile Send_private_message 
technosaurus


Joined: 18 May 2008
Posts: 4351

PostPosted: Mon 28 Jul 2014, 00:48    Post_subject:  

This is not the fastest way on _all_ systems, but pretty close to the fast inverse square method and more portable by using a simple binary split method
Code:
//replaces x with the floor of its base-2 logarithm
#define TO_MSB(x) do{int i=(sizeof(x)*8),r=-!x;while(i>>=1)x>>i?x>>=i,r+=i:0;x=r;}while(0)
//same but returns it to r
#define MSB(x,r) do{int i=(sizeof(x)*8);r=-!x;while(i>>=1)x>>i?x>>=i,r+=i:0;}while(0)

Explanation:
1. floor of its base-2 logarithm is just a fancy way of saying the position of the most significant bit.

Further info here:
http://codegolf.stackexchange.com/a/35211/21288


Code:
char *nthstring(const char *s, unsigned n){
   while(n--)while(*s++);
   return s;
}

//usage:
//static const char strings[]="hello\0world\0test";
//printf("%s\n",nthstring(strings,1));
//> world

_________________
Web Programming - Pet Packaging 100 & 101
Back to top
View user's profile Send_private_message 
Display_posts:   Sort by:   
Page 2 of 3 Posts_count   Goto page: Previous 1, 2, 3 Next
Post_new_topic   Reply_to_topic View_previous_topic :: View_next_topic
 Forum index » Off-Topic Area » Programming
Jump to:  

Rules_post_cannot
Rules_reply_cannot
Rules_edit_cannot
Rules_delete_cannot
Rules_vote_cannot
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group
[ Time: 0.1069s ][ Queries: 13 (0.0078s) ][ GZIP on ]