1

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:

  • The crux of this code is the outputting the correct elf_hash For example, if I enter "freelocal" , it should output "0x0bc334fc", as per the linked article ELF_DT_HASH
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).

  • regarding no.3 , the repeated runs with different result:
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!
cg79
  • 63
  • 5
  • Please ask one specific question per post. "Fix everything wrong with my code" is also considered too broad. – kaylum Jan 17 '22 at 21:51
  • 1
    Please remove line numbers. Use `cat`. `nd enter the same string` what string exactly do you enter? `quite a few warnings at compilation,` what warnings? Would be nice to please post them. `Type word for which` Well, `%hhu` scans _one number_, not a "word". For "words", use `%s`. – KamilCuk Jan 17 '22 at 21:51
  • `%hhu` is for entering a single character, not a word. Use `%s` for a word. – Barmar Jan 17 '22 at 21:53
  • I've answered your questions in my edit – cg79 Jan 18 '22 at 09:09
  • One more point remains open (after @chux answers) which is not related to the hash function: why the 'random' different results ? – cg79 Jan 18 '22 at 10:49
  • @Barmar: Thank you! Note: The term 'word', wasn't necessarily referring to a string (in C/C++), my bad for the confusion. There are few open points regarding string vs char-array issue, if you would: given that the hashing function expects an array of chars, how should the code be changed to deal only with char arrays ? By using scanf "%s" I am reading a string; how would i go about reading an array of chars? The "%c" specifier is the answer here ? Or perhaps a 'strcopy' (if possible from string -> char array) Also, what format spec. would the printf need to have in such case ? Thanks – cg79 Jan 18 '22 at 15:51
  • @KamilCuk: got it (reg. %hhu). What would the correct format specifier for scanning 'into' an array of chars be? what about into anarray of uint8_t please? Regarding warnings: elf_hash-calculaTor.c: In function 'main': elf_hash-calculaTor.c:18:1: warning: implicit declaration of function 'printf' [-Wimplicit-function-declaration] printf("Type word for which to calculate the elf-hash:"); ^~~~~~ elf_hash-calculaTor.c:18:1: warning: incompatible implicit declaration of built-in function 'printf' elf_hash-calculaTor.c:18:1: note: include '' or provide a declaration of 'printf' – cg79 Jan 18 '22 at 16:10
  • 1
    `note: include '' or provide a declaration of 'printf'` do it, include stdio.h. `What would the correct format specifier for scanning 'into' an array of chars be?` You can't scan an array. You can scan into one element of an array, in which case, iterate over array elements and scan into a single element. `of uint8_t please?` The most correct, would be `SCNd8` from `inttypes.h`. So like `#include int main() { uint8_t arr[20]; for (int i = 0; i < 20; ++i) { scanf("%"SCNd8, &arr[i]); } }`. If you are learning the language, consider https://stackoverflow.com/q/562303/9072753 – KamilCuk Jan 19 '22 at 08:44

1 Answers1

0

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);
  ...
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Thanks! I adjusted my code hopefully in the proper way - but still am not seeing the correct elf_hash for e.g. "freelocal" -see EDIT 2 Also, can you please answer on the different outputs, for same input entered ,Thanks ? – cg79 Jan 18 '22 at 09:10
  • @cg79 Of course the output is different as you are not using the same hash algorithm. Try your `elf_gnu_hash("")` --> 0x1505 (5381) which should be easy to see why as the loop does not iterated after the `unsigned long h = 5381;`. Now try `elf_hash("")` --> 0. Your `elf_gnu_hash(()` simply produces a different hash than the referenced `elf_hash()`. Your expectation that they should produce the same hash is unfounded. – chux - Reinstate Monica Jan 18 '22 at 10:09
  • d'oh .... apologies, my lack of sleep made a point here, heh, Thanks ! – cg79 Jan 18 '22 at 10:41