Friday, December 21, 2018

Converting the HEX dump of packets into libpcap Format using "text2pcap"


    Some time we may have the packet dumps in the ASCII hex dump format. In this format, the packet content will be shown as a string of HEX values. It is tough to analyze/decode the content of such packet manually. "text2pcap" is a command line utility available in most Linux distributions which is a handy tool to convert the packets from ASCII HEX dump format into "libpcap" format. The resultant "pcap" file can be viewed with "wireshark" and hence the packet analysis becomes easier.
    "text2pcap" utility takes a text file as input and generates an output file in "libpcap" format. This utility expects its input file to be formatted in certain order. Then only, the "pcap" file can be generated. Consider the below example.

    We are having a packet in the ASCII HEX dump format as given below. From this string of HEX values, it is very tough to analyze the packet. We want to convert it into "pcap" format so that we will be able to view it in the "wireshark" tool and analysis will become easier.

01 80 c2 00 00 00 00 03 b1 d1 2d 00 81 00 0f fc 00 26 42 42 03 00 00 00 00 81 80 00 00 03 b1 d1
2d 00 00 00 00 00 80 00 00 03 b1 d1 2d 00 80 15 00 00 14 00 02 00 0f 00 00 00 00 00 00 00 00 00

  • Let us copy this ASCII HEX dump values to a file "dump" as it is.
  • Invoke the "text2pcap" utility with this input file.
    • text2pcap -d dump pktcap.pcap
      Input from: dump
      Output to: pktcap.pcap

      -------------------------
      Read 0 potential packets, wrote 0 packets
  • The conversion of the HEX dump to ".pcap" file has failed as the data in the input file "dump" is not in the prescribed format.

Syntax of "text2pcap"
 text2pcap [options] [input_file] [output_file]  
     Here, input_file is having the ASCII HEX dump of packets and the output_file will be generated in "libpcap" format.
    -d --> This option will display debug messages related to "pcap" file generation.

Formatting the ASCII HEX Dump:
  1. Each byte should be displayed and surrounded individually with a space. 
  2. Each line begins with an  offset describing the position of each byte in the packet dump. Usually the offset value is specified in HEX format with more than two digits. 
  3. Each line can have any number of bytes; but the only requirement is the offset of the consecutive lines should be calculated properly. 
  4. The HEX dump is case-insensitive.
  5. Any line starting with # will be treated as comment and it will be ignored.

     Now, we format the input file "dump" as per the above guidelines and will try to generate the "pcap" file.


Input File after formatting cat dump

0000 01 80 c2 00 00 00 00 03 b1 d1 2d 00 81 00 0f fc
0010 00 26 42 42 03 00 00 00 00 81 80 00 00 03 b1 d1
0020 2d 00 00 00 00 00 80 00 00 03 b1 d1 2d 00 80 15
0030 00 00 14 00 02 00 0f 00 00 00 00 00 00 00 00 00

As we can see, each line starts with an offset which is specified in HEX format and each line is having a 16 bytes of data. Each byte is surrounded by space.
Generating the "pcap" File text2pcap -d dump pktcap.pcap
    Input from: dump
    Output to: pktcap.pcap
    Start new packet
    Wrote packet of 64 bytes at 0

    -------------------------
    Read 1 potential packet, wrote 1 packet

  Now, the "pcap" file has been successfully generated.

[root@bash temp]# ls
dump  pktcap.pcap
[root@bash temp]#


Reading the file "pktcap.pcap" in Wireshark:

    The generated "libpcap" file can be read using wireshark which will give us detailed info of the received HEX dump of packet.


Viewing the HEX Dump in libpcap format using wireshark
















Generating single "pcap" file from HEX dump of multiple packets:

    "text2pcap" allows the series of packet hexdumps present in a single input file to be converted into a single "pcap" file. The generated "pcap" file will have the series of converted packets. This can be achieved by starting the offset of each new HEX dump with zero.

     Consider the below example where HEX dump of two packets are specified in a single input file.

[root@bash temp]# cat dump
### HEX DUMP OF PACKET 1
0000 01 80 c2 00 00 00 00 03 b1 d1 2d 00 81 00 0f fc
0010 00 26 42 42 03 00 00 00 00 81 80 00 00 03 b1 d1
0020 2d 00 00 00 00 00 80 00 00 03 b1 d1 2d 00 80 15
0030 00 00 14 00 02 00 0f 00 00 00 00 00 00 00 00 00


### HEX DUMP OF PACKET 2
0000 2c b6 93 18 32 00 00 03 b3 d1 2d 00 81 00 00 03
0010 08 06 00 01 08 00 06 04 00 02 00 03 b2 d1 2d 00
0020 ac 1f 7e fa 2c b6 93 18 32 00 ac 1f 7e 65 00 00
0030 00 00 00 00 00 00 00 00 00 00 00 00
[root@bash temp]#

    Now convert this HEX dump into "pcap" file using "text2pcap" tool.


[root@bash temp]# text2pcap -d dump pktcap.pcap    
Input from: dump
Output to: pktcap.pcap
Start new packet
Start new packet
Wrote packet of 64 bytes at 0
Wrote packet of 60 bytes at 64

-------------------------
Read 2 potential packets, wrote 2 packets
[root@bash temp]#

Please find below the wireshark output for the generated "pcap" file which shows two packets.


Converting HEX dump of multiple packets into pcap format








References:
1. Manual page of "text2pcap" tool.

Sunday, October 28, 2018

How to fix "CONSTANT EXPRESSION RESULT" type coverity warnings in c code

Constant Expression Result - Coverity Warning:
    In this post we can discuss about a common logical error in the "if" condition evaluation statement which may lead to the "Constant Expression Result" type coverity warning in C code. Because of this logical error, the expression in the "if" condition evaluates to be either true or false always.
   Coverity tool will report "constant expression result" error when an expression is evaluated to be either true or false always irrespective of the value of the operands in that expression. That is, the expression's value does not depend on its operands. Consider the below C program.

Example 1: Expression always evaluates to be "false"

    In this program, we wanted to print the statement "Condition Met" only for the inputs red and green.

 #include <stdio.h>
typedef enum
{
    violet = 1,
    indigo,
    blue,
    green,
    yellow,
    orange,
    red
}tVIBGYOR;

void VerifyColour (tVIBGYOR input)
{
    if ((input == red) && (input == green))
    {
        if (input == red)
            printf ("Condition Met for RED\n");
        if (input == green)
            printf ("Condition Met for GREEN\n");
    }
}
int main ()
{
    VerifyColour (violet);
    VerifyColour (green);
    VerifyColour (red);
    VerifyColour (orange);
  
    return 0;
}

Output:

root@ubuntu:~/Programs# ./a.out
root@ubuntu:~/Programs#

    When we execute the program, the "Condition Met" statement is not at all being printed for any input value passed. The  reason is that, the below condition check in the "if" statement in the function "VerifyColour" always evaluated to be false.

     if ((input == red) && (input == green))

    In this statement we expect the variable "input" to have two different values at the same time whic is not possible. Even though when we pass the input as "red", the other condition of "input == green" will not be met. Similarly for the input "violet", none of the condition would be met. Eventually, the statement evaluated to be false irrespective of input arguments. So coverity reports this as "CONSTANT_EXPRESSION_RESULT" warning for this condition check.

How to Solve:

    If we change the "if" statement as below, the issue will get resolved.

    if ((input == red) || (input == green))

   With this change, the program will print the "Condition Met" statement when the input is either "red" or "green".

root@ubuntu:~/Programs# ./a.out
Condition Met for GREEN
Condition Met for RED
root@ubuntu:~/Programs#


Example 2: Expression always evaluates to be "true"

    In this example, we want to print the input value along with "Condition Met" statement except for the input values "red" and "green".

 #include <stdio.h>
typedef enum
{
    violet = 1,
    indigo,
    blue,
    green,
    yellow,
    orange,
    red
}tVIBGYOR;

void VerifyColour (tVIBGYOR input)
{
    if ((input != red) || (input != green))
    {
        printf ("Condition Met. Value=%d\n",(int)input);
    }
}
int main ()
{
    VerifyColour (violet);
    VerifyColour (green);
    VerifyColour (red);
    VerifyColour (orange);
  
    return 0;
}

Output:
root@ubuntu:~/Programs# ./a.out
Condition Met. Value=1
Condition Met. Value=4
Condition Met. Value=7
Condition Met. Value=6
root@ubuntu:~/Programs#

    In this program, the below "if" statement in the function "VerifyColour" is evaluated to be "true"  always.

    if ((input != red) || (input != green))

   When we pass the input as "red",  the second condition "input != green" gets satisfied and the condition passes. Similarly for input "violet", the expression is again is evaluated to be "true".

How to Solve:
    If we modify the expression as below, the program works as expected.

    if ((input != red) && (input != green))

    With this change, the program will print the input value except for the inputs "red" and "green".

root@ubuntu:~/Programs# ./a.out
Condition Met. Value=1
Condition Met. Value=6
root@ubuntu:~/Programs#




 

   

Saturday, October 27, 2018

A Relationship between Function Pointer and Function Calling Convention in "C"

C - Function pointer & Calling Convention - Relationship:
    There is a unique relationship between function pointer and function calling convention in C. The function calling convention is one of the parameters that define the signature of a function. Each function pointer can be used to manipulate the functions with a particular signature. So, a function with different calling convention cannot be manipulated by the same function pointer. 

What is Function Calling Convention in "C":
     
    When ever a function is called in C, a stack frame is created in the stack area for that function. Stack frame stores several information relevant to that function. The arguments passed to the function, local variables, return address, etc will be stored in that stack frame. When the execution of the function completes, the stack frame will be destroyed.
    The C function calling convention tells the compiler things such as
  • The order in which the function arguments are pushed onto the stack.
  • Stack Cleanup Responsibility: When the function execution completed, whether the caller or called function will take care of destroying the stack
    The calling convention belongs to a  function's signature. To know about what function's signature implies, click here. Some of the calling conventions used in C compilers are __stdcall, __pascal, __cdecl and __fastcall. Every compilers follow their own way to specify the calling convention during the function definitions/declarations. Because of this, it may be possible to get linking errors such as "unresolved external" if we try to link object files compiled with different compilers.

    For example, the Borland and Microsoft compilers mandates the specification of calling convention type between function return type and function name.

    //Borland and Mircrosoft calling convention specification
   <FnReturnType> <calling_convention_type> FnName(argument)

   Example: void __cdecl TestFunction(char *str);

    For the GNU GCC, the __attribute__ keyword is used to specify the function calling convention.
    <FnReturnType> __attribute__((cdecl)) FnName (arguments)

    Example: void __attribute__((cdecl)) TestFunction (char *str) ;

Function Pointer & Calling Convention Relationship:

    A function pointer always points to a function with specific signature. So, we cannot use the same function pointer to point functions with two different signature. As the calling convention of a function is one of the signature parameters, we cannot use the same function pointer to manipulate a function with two different calling convention.

Illustrative Example:
     Consider the below C program to understand the concepts introduced above.

#include <stdio.h>
int add (int,int); /* Function with default calling convention */
int sub (int,int); /* Function with default calling convention */
int __attribute__((fastcall)) sub_new (int,int) ; /* Function with __fastcall type calling convention */
int main()
{
    int var1 = 10, var2 = 20, rslt = 0;

   
    int (*FunPtr) (int,int) = NULL; /* A function pointer which accepts a function whose return
                                       type is integer and accepts two integer arguments and the
                                       function with default calling convention*/

    int __attribute__((fastcall)) (*NewFunPtr) (int,int) = NULL;  /* A function pointer with non-
                                                                                                          default calling convention */

    FunPtr = &add;

    rslt = FunPtr (var1,var2); /* Calling the function add */
    printf ("Addition Result:%d\r\n",rslt);

    FunPtr = sub;

    rslt = FunPtr (var1,var2); /* Calling the function sub */
    printf ("Subtraction Result:%d\r\n",rslt);

    FunPtr = sub_new; /* We are assigning a function with different calling convention */

    rslt = FunPtr (var1,var2); /* Calling the function sub_new */
    printf ("Subtraction with __fastcall calling type -->Result:%d\r\n",rslt);

    NewFunPtr = sub_new; /* We are assigning a function with proper calling convention */

    rslt = NewFunPtr (var1,var2); /* Calling the function sub_new */
    printf ("Subtraction with __fastcall calling type and __fastcall Fn.Ptr --> Result:%d\r\n",rslt);

    return 0;
}

int add (int val1, int val2)
{
    return (val1+val2);
}

int sub (int val1, int val2)
{
    return (val1-val2);
}

int __attribute__((fastcall)) sub_new (int val1, int val2)
{
    return (val1-val2);
}

Compilation Warning:
    When we compile this using gcc, it throws warning for possible incompatible pointer type assignment at the line "FunPtr = sub_new;"

root@ubuntu:~/Programs# gcc -Wall FnPtr2.c
FnPtr2.c: In function ‘main’:
FnPtr2.c:25:12: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
     FunPtr = sub_new; /* We are assigning a function with different calling convention */
            ^
root@ubuntu:~/Programs#

Output:

root@ubuntu:~/Programs# ./a.out
Addition Result:30
Subtraction Result:-10
Subtraction with __fastcall calling type -->Result:-938653831     <<< junk value is returned when we used function pointer with different calling convention.
Subtraction with __fastcall calling type and __fastcall Fn.Ptr --> Result:-10   <<< Result is proper when the calling convention matches.
root@ubuntu:~/Programs#


References:

 https://www.tenouk.com/Bufferoverflowc/bufferoverflowvulexploitdemo31.html

Wednesday, October 24, 2018

A Network Traffic Generator tool using Linux Utilities


    Most of the time in the development and testing of Networking products, we may need to test the product by injecting the traffic to it. We can use any traffic generator tools like Spirent or IXIA to construct and inject the traffic to our DUT (Device Under Test). These traffic generators are separate hardware devices that we need to purchase and for each type of feature on the device we need to get license too which is costlier.
   For simple testing, we can use the Linux utilities to construct and send the packet out of ethernet ports. We can connect our DUT to this ethernet port and test it.

   In this post we can see how to construct and send the packets on ethernet ports using Linux utilities. A prerequisite to use this script is that we need to have the ASCII hexdump of packet that we need to inject.

   The Linux utility "text2pcap" and open source tool "packEth" is used to generate and send out the traffic via particular ethernet port. The utility "text2pcap" is available by default in most Linux distributions. The "packEth" tool can be downloaded from here . Download the packEth tool for linux version.

    The "packEth" tool sends the packet given as input via an Ethernet interface that we specify. But the input file needs to be in "pcap" format. So, when we know the ASCII hexdump of packet that we need to send, we can use the utility "text2pcap" which will convert the text file which contains the packet content in ASCII hexdump format, into a "pcap" file. Then we can send that "pcap" file using the "packEth" tool.

text2pcap:
    This utility reads in an ASCII hex dump and writes the data described into pcap file.
 
    text2pcap -d <infile> <outfile>

    This command will read packet content from "infile" and  will generate the "outfile" in .pcap format. If there is any parse error while processing input file, it will be displayed on the screen. To know about the way of formatting the input file of "text2pcap" tool, click here.

How to install "packEth":
  • Download the "packEth" tool for Linux version here.
  • Extract the package using the command "tar xvjf packETH-1.9.tar.bz2"
  • Go to "packETH-1.9/cli" and give "make". This will generate the "packETHCli" utility inside that path. This utility will send the packet out of the specified eth port.
How to use "packETHCli":
      packETHcli -i <Interface> -m 1 -f  <pcap_file> 

      This command will send out one instance of the given packet "pcap_file" out of the given "Interface".

     Use the command "packETHcli -h" to know more about the usage of utility.

Illustration:

    Consider the scenario where we have a file "garp_ascii_hex" which contains a GARP packet in ASCII HEX format.

[root@centos-5-vm cli]# cat garp_ascii_hex
0000  ff ff ff ff ff ff 02 02 02 02 02 02 08 06 00 01   ................
0010  08 00 06 04 00 01 02 02 02 02 02 02 c0 a8 01 01   ................
0020  ff ff ff ff ff ff c0 a8 01 01 00 00 00 00 00 00   ................
0030  00 00 00 00 00 00 00 00 00 00 00 00               ............
[root@centos-5-vm cli]#

   Now, we want to send this packet out of ethernet port using "packETHcli" utility. As "packETHcli" accepts only the files in .pcap format, we use the "text2pcap" utility to convert the above packet from ASCII HEX format into .pcap format.

    ./text2pcap  -d garp_ascii_hex  garp_pkt.pcap

[root@centos-5-vm cli]# text2pcap garp_ascii_hex garp_pkt.pcap
Input from: garp_ascii_hex
Output to: garp_pkt.pcap
Wrote packet of 60 bytes at 0
Read 1 potential packet, wrote 1 packet
[root@centos-5-vm cli]#


Note: The "text2pcap" utility will process the input file only when its content are in particular format. The man page says,
      "Text2pcap understands a hexdump of the form where each byte is individually displayed and surrounded with a space. Each line begins with an offset describing the position in the file. The offset is a hex number of more than two hex digits."

     Now, we want to send the packet "garp_pkt.pcap" out of "eth0" interface. We use the packETHcli utility to achieve the same.

    packETHcli -i eth0 -m 1 -f  garp_pkt.pcap

   This will send out the packet "garp_pkt.pcap" from eth0 interface.

    


Sunday, October 14, 2018

How to fix "BAD SIZEOF" type coverity warnings in C code

Bad sizeof - Coverity Warning:
   The "sizeof" is an unary operator in C which is used to compute the size of its operand. The "BAD_SIZEOF" is a type of coverity warning which will be reported when there is a possibility of logical error in the usage of the "sizeof" operator. Consider the program given below.

#include <stdio.h>
#include <string.h>
int main()
{
    char src_string[10]="C_Program", out_string1[10] = {0}, out_string2[10] = {0};
    char *ptr = NULL;

    ptr = src_string;

    printf ("src_string=%s ;; *ptr=%s\n", src_string, ptr);

    memcpy(out_string1, src_string, sizeof(src_string));
    memcpy(out_string2, src_string, sizeof(ptr));     /* <<<<< bad_sizeof warning will be reported by coverity at this line >>>>>*/

    printf ("Out_String1=%s ;; Out_String2=%s\n",out_string1, out_string2);

    printf ("sizeof(src_string)=%u ;; sizeof(ptr)=%u\n",sizeof(src_string), sizeof(ptr));
    return 0;
}

    In this program, we try to copy the string "C_Program" into two different output variables using the "memcpy" function. We assign the base address of the character array "src_string" to a character pointer "ptr". We can print the string "C_Program" by using either "src_string" or "ptr". But when we try to calculate the size of these variables, this will result in different values.  Because of this reason, when we try to copy this string to output variables using "memcpy", the results are different.
    When we execute the program we get the below output.

Output:

src_string=C_Program ;; *ptr=C_Program    <<<< Both src_string && ptr prints the string properly
Out_String1=C_Program ;; Out_String2=C_Pr     <<< The values copied into out_string1 and out_string2 are different.
sizeof(src_string)=10 ;; sizeof(ptr)=4

     From the above output, we can understand that the string "C_Program" is being printed properly using "src_string" and "ptr". While copying to output variables, the value is properly copied into the variable "out_string1". Whereas for the variable "out_string2", only partial string was copied.
    In the first "memcpy" statement, we used the "sizeof(src_string)". This will calculate the size of the argument "src_string" which is an array. In this case it happens to be 10. So, all the characters are properly copied into the variable "out_string1".
    In the second "memcpy" statement, we used "sizeof(ptr)". The argument "ptr" is a pointer variable whose size is 4 bytes. So, only 4 bytes are being copied into "out_string2". The coverity tool will report this second sizeof statement as "bad_sizeof". We wanted to copy the entire string pointed by "ptr" into the variable "out_string2". But due to incorrect use of sizeof operator, the result went wrong.

How to Solve:
    We can re-write the second "memcpy" statement as given below which will resolve the error.

    memcpy (out_string2, src_string, strlen(ptr));

    Otherwise, we can use the first memcpy statement alone to copy the string.


    This is one example which illustrated the incorrect usage of "sizeof" operator.Whenever coverity reports "bad_sizeof" warning, verify that the argument passed to the "sizeof" operator is proper and correct the statement in appropriate way.

Thursday, September 27, 2018

An introduction to declare, initialize and access a function pointer in C

     As we know that the pointers are variables which holds the address of another variable. Many of us might have used pointers such as integer pointer, character pointer, pointer to a structure, etc. in our usual C programming. But the use of C function pointers is very occasional. In this post, we can look at the ways to declare, initialize and access the function pointers.

What is Function Pointer:
    A function pointer is a variable, which holds the address of a function. As we know that for each variable in C, one address can be associated. This address is the memory location in main memory where the value of the variable is being stored at the run time. Like variables, each function is also has an address. Functions are sequence of instructions present in a main memory. The address of each function is the address of the first instruction of that function definition.

Function's Signature:
    Each function is having a specific signature. That is, a signature of a function is defined by the number of arguments they accept and the type of those arguments and the return type.

   For example, the below two functions have the same signatures.

   void function1 (int arg1, char arg2);
   void function2 (int val1, char val2);

   The functions "function1" and "function2" has the same signatures as they match in the number and type of arguments accepted and having the matching return type.
 
   void function3 (int data1, char data2, int data3);
   void function4 (int arg1, int arg2);

   The "function3" is having the different signature than the functions "function1" and "function2" as it differs in the number of arguments accepted.  Even though "function4" is accepting two arguments, it is having different signature than the "function1" and "function2" as its 2nd argument type differs.


Why does the Signature of a function matter?
    A function pointer always points to a function with a specific signature. So, we cannot use the same function pointer to point functions with two different signatures.
    For normal pointers, using typecast we can store address of variable of one particular type into a pointer of different type. Consider the below case.

   int *ptr = NULL;
   char data='v';
   ptr = (int*)&data;

  In the above example, we are storing the address of character variable into integer pointer using typecast. But this is NOT possible with function pointers which makes it unique and different.

Function Pointer Declaration:
    The function pointer can be declared as given below.
     <return-type> (*FnPtrName) (<argtype arg1>, <argtype arg2>,....<argtyp argN>)
                                          or
     <return-type> (*FnPtrName) (void)

  In the above syntax, the return-type can be void or any valid return types. FnPtrName can be any variable name which will be used for accessing the function pointers. It can accepts any number of arguments or it can be void.

Example:
  int (*FunPtr) (int,int) = NULL;
  
  In the above example, the function pointer is named as "FunPtr" and it accepts two integers as arguments and returns integer value. This pointer is initialized to NULL during definition of that variable.
  This function pointer can be used to store the address of any functions which is matching the signature of this function pointer; i.e any functions which is accepting two integer arguments and  returns integer results.

 
 Assigning an address to a Function pointer:

    Consider the below two function prototypes.
    int add (int,int);
    int sub (int,int);


    The functions "add" and "sub" accepts two integer arguments and returns integer results. These functions having the same signature as that of the function pointer defined in the previous example. So, we can manipulate these functions using the function pointer in example.
   We can assign the address of a function to a function pointer in two ways.

    FunPtr = add; (or) FunPtr = &add;

   Both of the above initialization are valid. The starting address of those functions will be assigned to the function pointer.

Comparing Function Pointers:
    We can compare a value of the function pointer using "==" operator as given below.

     if ((FunPtr == add) ||(*FunPtr == add))   /* We can compare directly specifying the function pointer or we can compare by de-referencing the function pointer ; both are same */
        printf ("Function Pointer Pointing to add function\n");
     else if ((FunPtr == &sub) || (*FunPtr == &sub))
       printf ("Function Pointer Pointing to sub function\n");

   When we specify "add" or "&sub", the starting address of those functions  are compared with the function pointers.

Invoking Function using a function pointer:
    We can call a function using function pointer in two ways. We can directly use the name of the function pointer or we can de-reference that function pointer.

    rslt = FunPtr (10,20); (or) rslt = (*FunPtr) (10,20);


Example:
    In this example we will put together the concepts introduced above.

 #include <stdio.h>
int add (int,int);
int sub (int,int);
int main()
{
    int var1 = 10, var2 = 20, rslt = 0;

    int (*FunPtr) (int,int) = NULL;

    FunPtr = &add;

    rslt = FunPtr (var1,var2);    /* Calling function "add" using function pointer */
    printf ("Addition Result:%d\r\n",rslt);

Tuesday, September 25, 2018

Compiling a C code using GCC for 32-bit machine architecture on a 64-bit machine


    Many of us aware of the fact that the 64 bit version of machine architecture will have the backward compatibility to lower versions. An application built for 32 bit version of Linux machine can run seamlessly on 64 bit version also, but the vice versa is not true. So, if we compile a C code on 64 bit version of Linux, it cannot be executed on the 32 bit version of Linux.
    By default, GCC builds an application for the native machine architecture. So, on 64-bit machine, the GCC builds an application for 64-bit architecture. If we want an application built on a 64-bit machine to run on both 32-bit and 64-bit machines, we can achieve it using the special compilation flag of GCC.

The -m Flag:
    GCC provides a special  compilation flag "-m" to specify the machine architecture for which the application needs to be built.
    To build for 32-bit version, specify the compilation flag as "-m32", whereas for 64-bit version, use the flag "-m64".

    Note: To execute a 32-bit application on a 64-bit machine, we need to have the 32-bit version of dynamic libraries required by that application on that 64-bit machine; otherwise the application cannot be executed.

Examples:

test.c

#include <stdio.h>
int main()
{
    printf ("Welcome\r\n");
    return 0;
}

32-bit Compilation:

gcc -m32 -o 32bitExe test.c

This Command will compile the "test.c" for 32-bit machine architecture and creates the executable with the name "32bitExe".

 Running the executable, will give the below output.

./32bitExe
Welcome


64-bit Compilation:

gcc -m64 -o 64bitExe test.c

This command will compile the code "test.c" for 64-bit machine architecture and creates the executable with the name "64bitExe".

Running the executable, will give the below output.

./64bitExe
Welcome


How to identify the executable is 32-bit or 64-bit version:

    The linux command "file" can be used to identify whether an executable is of type 32-bit or 64-bit.

    Syntax: file <executable-name>

Example:
We wanted to know whether the executable name "32bitExe" is a 32-bit or 64-bit executable. 

file 32bitExe
32bitExe: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.0.0, BuildID[sha1]=0xd4f96ae7862c856df70e8aa9fe54aeb1b41992df, not stripped

As highlighted in bold above, the output of the file command clearly specifies that the executable "32bitExe" is a 32-bit version of executable.

Similarly, for the executable "64bitExe",

file 64bitExe
64bitExe: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.4.0, BuildID[sha1]=0x14a6ae7113cedf4945c25ad5b599227f85cb46ca, not stripped


Thursday, September 20, 2018

An overview of "#" operator in C - The "C" Stringizing Operator

    In this post, I am going to talk about the stringizing operator in C. We know that the symbol "#" is used in C preprocessor directives (#define statements). In addition, it has special functionality. The # is used as stringizing operator in C.This operator generates a double quoted string when it is preceded by some multi-word string. This multi-word string can have variable name, random string, numbers, etc. This operator can be used only in the macro expansions.

Sample Program:

#include <stdio.h>
#include <string.h>
#define MAXVALUE 10
#define LOG_FAILURE(x) if(x) \
                            /* Condition Met; no need to log*/; \
                        else \
                            LogFn (#x,__func__,__LINE__)

void LogFn(const char *logstr, const char *FnName,unsigned int line)
{
    printf ("LOG: FAILED CONDITION -> %s : In FUNCTION -> %s: In LINE -> %u\n",
                logstr, FnName, line);
}

int main ()
{
    int testval = 5;
    char name[] = "NAMETEST";

    LOG_FAILURE ((testval > MAXVALUE) && "Comparing testval and MAXVALUE"); // This will log the statement as the test result fails.

    testval = 15;

    LOG_FAILURE ((testval > MAXVALUE) && "Comparing testval and MAXVALUE"); // This will not be logged as the test result passes

    testval = 2;

    LOG_FAILURE ((strlen(name) > MAXVALUE) && "Comparing string length and MAXVALUE"); // This will be logged as the test result fails.

    return 0;
}


Output:

LOG: FAILED CONDITION -> (testval > MAXVALUE) && "Comparing testval and MAXVALUE" : In FUNCTION -> main: In LINE -> 20
LOG: FAILED CONDITION -> (strlen(name) > MAXVALUE) && "Comparing string length and MAXVALUE" : In FUNCTION -> main: In LINE -> 28

Expanded source code after Macro Expansion:

# 9 "stringize_oper1.c"
void LogFn(const char *logstr, const char *FnName,unsigned int line)
{
    printf ("LOG: FAILED CONDITION -> %s : In FUNCTION -> %s: In LINE -> %u\n",
                logstr, FnName, line);
}

int main ()
{
    int testval = 5;
    char name[] = "NAMETEST";

/* The macro is expanded after preprocessing; Note that the argument preceded by # has now been converted into double-quoted string */
    if((testval > 10) && "Comparing testval and MAXVALUE") ; else LogFn ("(testval > MAXVALUE) && \"Comparing testval and MAXVALUE\"",__func__,20);

    testval = 15;