22-May-2016: C/C++ pointers: yet another abuse

The note below has been copypasted to the Reverse Engineering for Beginners book

(For those who have a hard time in understanding C/C++ pointers).

Let's continue to abuse C/C++ language traditions and sane programming style (first part here). Here is an example on how to pass values in pointers:

#include <stdio.h>
#include <stdint.h>

uint64_t multiply1 (uint64_t a, uint64_t b)
{
	return a*b;
};

uint64_t* multiply2 (uint64_t *a, uint64_t *b)
{
	return (uint64_t*)((uint64_t)a*(uint64_t)b);
};

int main()
{
	printf ("%d\n", multiply1(123, 456));
	printf ("%d\n", (uint64_t)multiply2((uint64_t*)123, (uint64_t*)456));
};

It works smoothly and GCC 4.8.4 compiles both multiply1() and multiply2() functions identically!

multiply1:
	mov	rax, rdi
	imul	rax, rsi
	ret

multiply2:
	mov	rax, rdi
	imul	rax, rsi
	ret

As long as you do not dereference pointer (in other words, you don't read any data from the address stored in pointer), everything will work fine. Pointer is a variable which can store anything, like usual variable.

By the way, it's well-known hack to abuse pointers a little called tagged pointers. In short, if all your pointers points to blocks of memory with size of, let's say, 16 bytes (or it is always aligned on 16-byte boundary), 4 lowest bits of pointer is always zero bits and this space can be used somehow. It's very popular in LISP compilers and interpreters. Read more about it: http://yurichev.com/writings/C-notes-en.pdf#page=20&zoom=auto,-107,595.

Update (23-May-2016) Slava "Avid" Kazakov has asked, why signed imul instruction is used while pointer has type uint64_t? Any idea?


My other blog posts about C/C++ pointers: [ 1 | 2 | 3 | 4 | 5 ]


This open sourced site and this page in particular is hosted on GitHub. Patches, suggestions and comments are welcome.


→ [list of blog posts, my twitter/facebook]

The page last updated on 09-October-2016