ctype-conversionprintfscanfunsigned-char

Type conversion issues unsigned char, string, hex


The following code has several issues - for which I'm kindly asking for your input / corrections / feedback - of various types: first, I can't get it to do what I'd like to, namely pass it a "word" and have it output its elf_hash. The code for the elf_gnu_hash ( EDIT 3: This should have been elf_hash, hence my surprise for the wrong hash below ) function is presented ELF_DT_HASH. What I'm trying to do is incorporate this function i a small standalone program, but I seem to not be able to get it right, i.e. the output printed is by no means that one which is expected (comparing to mentioned article).

Second, I'm sure the code exposes (obvious) to anyone doing C programming - me excluded from this 'list' misunderstanding of data types, conversions, and so on and I'd appreciate some clarifications / hints regarding some common rookies' (me included) misunderstandings. Third, and most intriguing is that each time i compile and run this program, and enter the same string at the scanf functions, it prints a different result !

There are quite a few warnings at compilation, but honestly I am not sure how to fix them. Could you guys help me out fix this issue + address some misunderstanding / misuse of C ?

I'd also appreciate some inputs on input sanitization (i.e. avoiding bufferoverflows and so on).

Am compiling it -in case it matters, not sure - like so:

gcc -Wall elf_hash-calculaTor.c && ./a.out

Thanks

As a bonus: is this the algorithm used in Linux OS amd64 elf binary files, like f.e.

$ file hexedit
hexedit: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=d3f6cd413abaa25d5b7a2427f05598f3152e2efa, for GNU/Linux 3.2.0, stripped

, or is this one DT_GNU_HASH instead ?

#include <stdint.h>                                                                                                                                                         
  
/** The ELF symbol GNU hashing function */
static unsigned long elf_gnu_hash(const unsigned char*name) {
  unsigned long h = 5381;
  unsigned char c;
  while ((c = *name++) != '\0') {
    h = (h << 5) + h + c;
  }
  return h & 0xffffffff;
}
 
int main(int ac,char **av){
  unsigned char in[10] = "\0";
  printf("Type word for which to calculate the elf-hash:");
  scanf("%hhu", &in);
  printf("Typed in:");
  printf("%hhu\n", in);
  printf("processing elf-hash:\n");
  //elf_gnu_hash(in);
  // following nok: printf("%#lx\n", elf_gnu_hash("freelocal"));
  printf("%#lx\n", elf_gnu_hash(in)); 
  printf("%s", "Thanks guys!");
}

EDIT

: To answer your questions:

elf_hash("freelocal") = 0x0bc334fc

, which in my case does not.

Is it because i enter a string (with scanf "%s", but the function expects a char (pointer?) which can be -if my understanding is correct - the first array of a char array (or is it that this cast from string to char-array is done automatically in C ?). The function then goes on to traverse all the chars in this array:

...   
while ((c = *name++) != '\0') {

and does some bit-wise shifting.

The intermediary printf, was serving just to echo out what was typed in and to proove that I got the type conversion right (which I also didn't).

tox@tox-bookp:/var/tmp$ ./a.out 
Type word for which to calculate the elf-hash:cucu
Typed in:126
processing elf-hash:
0x1505

 
tox@tox-bookp:/var/tmp$ ./a.out 
Type word for which to calculate the elf-hash:cucu
Typed in:62
...
 
tox@tox-bookp:/var/tmp$ ./a.out 
Type word for which to calculate the elf-hash:cucu
Typed in:174
...

EDIT 2

The code now looks like so (based on @chux's comments)

int main(int ac,char **av){
unsigned char in[10] = "";
printf("Type word for which to calculate the elf-hash:");
//scanf("%hhu", &in);
//printf("%hhu\n", in);
if (scanf("%9s", in) == 1) {
    printf("Typed in:");
    printf("<%s>\n", in);
    printf("processing elf-hash:\n");
//elf_gnu_hash(in);
// following nok:
    printf("%#lx\n", elf_gnu_hash("freelocal"));
    printf("%#lx\n", elf_gnu_hash(in));
    }                                                      
printf("%s\n", "Thanks guys!");
}

but still outputs wrong elf_hash :

Type-in item for which to calculate the elf-hash:freelocal
Typed in:<freelocal>
processing elf-hash:
0xe3364372   **<- is this ok, and if so, why ?**
0xe3364372   **<- incorrect** 
Thanks guys!

Solution

  • pass it a string ("word") and have it output its elf_hash.

    Use "%s" with a width limit to read user input and save as a string, not "%hhu" (which is useful to read numeric text in and save as a byte).

    unsigned char in[10] = "\0";  // Can simplify to ""
    
    // scanf("%hhu", &in);
    // printf("%hhu\n", in);
    
    if (scanf("%9s", in) == 1) {
      printf("<%s>\n", in);
      ...