Performance difference when accessing using pointer and double pointer - c

Is there any performance difference when we access a memory location by using a pointer and double pointer?
If so, which one is faster ?

There is no simple answer it, as the answer might depend in the actual machine. If I remember correctly some legacy machines (such as PDP11) offered a 'double pointer' access in a single instruction.
However, this is not the situation today. accessing memory is not as simple as it looks and requires a lot of work, due to virtual memory. For this reason - my guess is that double reference should in fact be slower on most modern machines - more work has to be done to translate two addresses from virtual addresses to physical addresses and retrieving them - but that's just educated guess.
Note however, that the compiler might optimize 'redundant' accesses for you already.
For my best knowledge however, there is no machine that has faster 'double access' than 'single access', so we can say that single access is not worse than double access.
As a side note, I believe in real life programs, the difference is neglectable (comparing to anything else done in the program), and unless done in a very performance sensitive loop - just do whatever is more readable. Also, the compiler might optimize it for you already if it can.

Assuming you are talking about something like
int a = 10;
int *aptr = &a;
int **aptrptr = &aptr;
Then the cost of
*aptr = 20;
Is one dereference. The address pointed to by aptr must first be retrieved and then the address can be stored to.
The cost of
**aptrptr = 30;
Is two dereferences. The address pointed to by aptrptr must first be retrieved. Then the addess stored in that address must be retrieved. Then this address can be stored to.
Is this what you were asking?
Therefore, to conclude using a single pointer is faster if that suits your needs.
Note, that if you access a pointer or double pointer in a loop, for example,
while(some condition)
*aptr = something;
or
while(some condition)
**aptrptr = something;
The compiler will likely optimize so that the dereferencing is only done once at the start of the loop, so the cost is only 1 extra address fetch rather than N, where N is the numnber of times the loop executes.
EDIT:
(1) As Amit correctly points out the "how" of pointer access is not explicitly a C thing... it does depend on the underlying architecture. If your machine supports a double dereference as a single instruction then there might not be a big difference. He is using the index deferred addressing mode of the PDP11 as an example. You might find out that such an instruction still chews up more cycles... consult the hardware documentation and look at the optimization that your C compiler is able to apply for your specific architecture.
The PDP11 architecture is circa the 1970s. As far as I know (if someone knows are modern architecture that can do this pleas post!), most RISC architectures and don't have such a double dereference and will probably need to do two fetches as far as I am aware.
Therefore, to conclude using a single pointer is probably faster generally, but with the caveat that specific architectures may handle this better than others and compiler optimizations, as I discussed, could make the difference negligible... to be sure you just have to profile your code and read up about your architecture :)

Let's see it in this way:
int var = 5;
int *ptr_to_var = &var;
int **ptr_to_ptr = &ptr;
When the variable var is accessed then you need to
1.get the address of the variable
2.fetch its value from that address.
In case of pointer ptr_to_var you need to
1.get the address of the pointer variable
2.fetch its value from that address (i.e, address of the variable var)
3.fetch the value at the address pointed to.
In third case, pointer to pointer to int variable ptr_to_ptr, you need to
1.get the address of the pointer to pointer variable
2.fetch its value from that address (i.e, address of the pointer to variable ptr_var)
3.again fetch its value from the address fetched in the second step(i.e, address of the variable var)
4.fetch the value at the address pointed to.
So we can say that accessing via pointer to pointer variable is slower than that of pointer variable which in turn slower than that of normal variable accessing.

I got curious and set up the following scenario:
int v = 0;
int *pv = &v;
int **ppv = &pv;
I tried dereferencing the pointers and took a look at the disassembly, which showed the following:
int x;
x = *pv;
00B33C5B mov eax,dword ptr [pv]
00B33C5E mov ecx,dword ptr [eax]
00B33C60 mov dword ptr [x],ecx
x = **ppv;
00B33C63 mov eax,dword ptr [ppv]
00B33C66 mov ecx,dword ptr [eax]
00B33C68 mov edx,dword ptr [ecx]
00B33C6A mov dword ptr [x],edx
You can see that there is an additional mov instruction for dereferencing there so my best guess is: double dereferencing is inevitably slower.

Related

Are C pointer's created on demand?

In C, we have data, and we have pointers. Pointers by themselves are binary data. So, at the hardware level there is no difference between data and pointers. Pointers must be an implementation. If we have a variable, that variable has two properties, the data and the address, which itself is a data, in a sense this creates an infinite pointer loop kind of thing. Since every pointer is a data, they must have a pointer that points to them, and the pointer that points to the pointer must have a pointer, and so on.
This type of implementation would only make sense if pointers are created on demand. Let's say we create a variable called a, does C immediately assign a pointer to this variable right after the variable being declared? Or is it when I explicitly try to pull the pointer by doing &a that C creates a pointer according to some internal algorithm?
in a sense this creates an infinite pointer loop kind of thing. Every pointer must have a parent pointer
This is logically incorrect. It's like saying: "A pointer is a street address. Every person has a street address. Therefore a street address is a pointer."
Pointers are variables containing addresses, but that doesn't make addresses pointers... something can have an address without a pointer used to access that address. Just like your machine code can contain integer values without them being stored in int variables.
Or is it when I explicitly try to pull the pointer by doing &a that C creates a pointer according to some internal algorithm?
Yes, kind of. Here the address is actually used by the program so the &a address must be stored somewhere. You can think of it as a temporary pointer variable if it helps. In practice, if we disassemble this code:
int a;
printf("%p\n", &a);
Then on gcc x86 this just results in a "load effective address" instruction. That is, the compiler stores the address in a register which is then passed on to printf as per that function's calling convention.
Your description is all wrong. It seems you are confusing C pointers and memory addresses at execution time. It's completely different things.
Pointers in C are no different from other data types. You get a pointer to type T only when you define one, i.e. like T* p; Just like you only get an int object when you define one (e.g. int a;).
At machine level it's completely different. In order to access objects (aka variables) stored in memory, the CPU needs a way to calculate the address of that object. The C standard does not care how it's done. It's an implementation detail that may differ from system to system.
Many implementations uses a "stack pointer" (stored in a CPU register) as reference for other variables. Instead of knowing the exact address of an object, the address is found as "value of stack pointer" plus an offset (i.e. SP+offset). This offset is then hardcoded into the execution binary, i.e. the instruction set of the CPU can have an instruction that do stuff like: "Read the memory at address SP+fixed_offset and store it in register X".
Take a look at this simple (and rather stupid) function:
unsigned long foo(unsigned long x)
{
unsigned long y = x;
putchar('a');
return y + x;
}
This defines two "unsigned long" objects and return their sum. Using godbolt.org, gcc 11.2, and flag -fomit-frame-pointer (no optimization to keep things simple), I get this machine code (with my comments added):
foo:
sub rsp, 40 // Change stack pointer to reserve 40 bytes
mov QWORD PTR [rsp+8], rdi // Save the passed value (i.e. register rdi)
// in object x at memory address rsp+8
mov rax, QWORD PTR [rsp+8] // Read object x into register rax
mov QWORD PTR [rsp+24], rax // Save rax in object y at memory address rsp+24
// So this is really y = x
mov edi, 97 // These are just
call putchar // putchar('a');
mov rdx, QWORD PTR [rsp+24] // Read object y into register rdx
mov rax, QWORD PTR [rsp+8] // Read object x into register rax
add rax, rdx // rax = rax + rdx, i.e. rax = y + x
add rsp, 40 // Restore stack pointer, i.e. release
// the 40 bytes
ret // Return. The returned value is in register rax
So on this specific system the memory address of x is found as "stack pointer + 8" and the memory address of y is found as "stack pointer + 24". From the machine code we can't tell the actual memory address of the variables as it depends on the value of the stack pointer (rsp) when the function is called.
The lesson is that - yes, at machine level there is a way to get the memory address of x and y but there is no such thing as an automatically created and stored pointer to any of them.
Now for fun - the same code compiled with -O2 gives:
foo:
push rbx
mov rsi, QWORD PTR stdout[rip]
mov rbx, rdi
mov edi, 97
call putc
lea rax, [rbx+rbx]
pop rbx
ret
Take a look at the code and see if you can find x and y ;-)
(but - to repeat - all this is not described by the C standard, it's just how it's done on this specific system).
BTW Also be aware that objects/variables define by the C code may exist only in CPU registers, i.e. the are never written to memory and consequently they don't even have an address.
Every variable is stored in the memory . The address (pointer) is not stored separately, it is simply the location of the variable.
(This is actually more complex than that: Some variables might normally stay in processor registers instead of RAM, but if you take their address, the compiler might store them in memory so that the address can be taken. Or if you just print the address, it might invent a fake address for them.)
If you take the address of a variable and store it in a pointer, you create a new variable, and assign the value of the address of the other variable. But the address of this new variable is not stored separately, it is simply the location of the variable.
There is no "infinite pointer loop", unless your code makes infinite number of variables and your computer has infinite memory.
What determines the address then? How does the program know where the variable is stored?
This is controlled by the operating system, which gives your program memory blocks based on the memory allocations you make. Your program determines (at compile time) which variable is in which address relative to this memory block.
I would not say "we have data, and we have pointers". Yes, pointers are different, but saying it this way doesn't really capture what's different about them.
Any variable has a location (also called an address), and a value (perhaps also called "contents"). If you say
int i = 5;
the value is 5, and we're not precisely sure where the location is (because we usually don't care), although the identifier i helps us keep track of it, whatever it is. But there are definitely two things, the location or address, and the contents or value.
If you say
int *ip = &i;
once again you have a variable named ip, and a value, which in this case is a pointer, or an address, and what it's the address of is the same as that other variable i. And then there's also a value in the pointed-to location. So you now have three things:
the variable ip, and
its value, which is "pointer to i", and
the pointed-to value, which is 5.
Almost nothing gets "created on demand". The variable i got created because you requested it. The variable ip got created because you requested it.
You can draw a picture like this to help you keep track of things:
+---------+
i: | 5 |
+---------+
^
|
+-------|-------+
ip:| * |
+---------------+
The only thing that happens automatically, behind your back, that you can't necessarily see, is the assignment of some actual, numeric addresses for your variables. You can see those if you print them out using %p:
printf("address of i: %p\n", &i);
printf("address of ip: %p\n", &ip);
and you will notice that ip holds i's address:
printf("value of ip: %p\n", ip);
or you can look at everything — i's two things, and ip's three things — like this:
printf("i: loc %p, value %d\n", &i, i);
printf("ip: loc %p, value %p, pointed-to value %d\n", &ip, ip, *ip);
To see what's going on a little more explicitly, let's write this as an actual program. For the moment, I'm going to have the variables i and ip be "global" variables, although this is unusual, because normally they'd be "local" variables, declared inside main. Also I'm going to declare a third variable j.
#include <stdio.h>
int i = 5;
int j = 66;
int *ip = &i;
int main()
{
printf(" i: loc %p, value %d\n", &i, i);
printf(" j: loc %p, value %d\n", &j, j);
printf("ip: loc %p, value %p, pointed-to value %d\n", &ip, ip, *ip);
}
the output I get is
i: loc 0x10837b018, value 5
j: loc 0x10837b01c, value 66
ip: loc 0x10837b020, value 0x10837b018, pointed-to value 5
You'd get different addresses on your computer, but basically a similar pattern.
If you're on a Unix-like system, you can run the nm command to see your program's "namelist", or symbol table, which is a list of all the identifiers in your program, and their addresses. When I run it on the program above, I get something like this:
$ nm a.out
000000010837b018 D _i
000000010837b01c D _j
000000010837b020 D _ip
0000000108370ec0 T _main
This shows me that my program has three things in the "data" segment, which are my variables, and one thing in the "text" segment, which is my main() function. Lo and behold, the locations listed by the nm program for my two variables exactly match what was printed when the program ran. (Although there's a complication here; see below.)
Now that we know where the variables actually are, we could draw a slightly different picture:
+---------+ +---------+
10837b018: | 5 | 10837b01c: | 66 |
+---------+ +---------+
^
|
+-------|-------+
10837b020:| * |
+---------------+
This shows us that, basically, the names or identifiers we use for things in our programs — like i, j, ip, and main — are like labels or shorthands for the addresses in memory where these things are stored. (In fact, these identifiers are therefore kind of like pointers in their own right, although I hesitate to say this, because it might confuse the issue.)
Another way to think of it is this. Imagine you live in a large apartment building. In the lobby is a large row of mailboxes, one for each apartment. Each mailbox, naturally, has a label on or next to it giving the apartment number. So the apartment numbers are like addresses, and the contents of the mailbox are like values.
Finally, two footnotes. On a modern system, the nm command probably won't print out addresses that are the same as your program did, after all, due to something called "address space randomization".
When you print pointers, strictly speaking you should cast them to void *, like this:
printf(" i: loc %p, value %d\n", (void *)&i, i);
printf("ip: loc %p, value %p, pointed-to value %d\n", (void *)&ip, (void *)ip, *ip);
C describes abstract machine, where pointer is pointer, and value is value (distinct from pointer).
When it comes to concrete machine, a pointer or a value may be saved in a register (which eliminates the need and the possibility of pointer to it). So you don't have infinite pointer loop, ultimately you have it in a CPU register.
When you compile your program, there may be no correspondence between C code and machine code, especially if optimizations ae enabled, so that &a actually may create creates no pointer (indirection optimized out), whereas b may create a pointer (added indirection to pass large structure).
You are worrying about things that the compiler handles.
When you assign a variable a, the compiler assigns it to a specific memory location or register - the address. The processor knows this address, and using the address, it can access the value of the variable. It doesn't need to keep a separate variable to remember the address.
There are multiple things a processor can do with the address, depending on the operations it supports, but the most common and the most relevant are direct addressing (access the value at the address number given to you in the operation), indirect addressing (access the value at the address number given to you in the operation AND THEN threat that value like an address and access ANOTHER value) and immediate addressing (treat the number given to you as a regular number). Respectively, they match a, *a and &a in C (this is way oversimplified though).
Conclusion - no, creating a pointer won't create an infinite amount of pointers, in order to keep track of the pointers. The processor treats everything the same - addresses are just values and values can be used as addresses.
This is an answer to your comment to S.Ptr answer.
The processor doesn't "know" anything.
The only thing a processor can do is execute instructions: things like "add two numbers together", "put this variable in RAM"... Before modern compiled programming languages like C all programs where created by listing instructions we wanted the processor to execute. A simple addition could have looked like this:
store 10 in memory at address 1
store 5 in memory at address 5
load the value at address 1 into register A
load the value at address 5 into register B
add B to A and store the result in B
store the result of B in memory at address 2
The programmer had to remember where they put everything because the CPU doesn't "understand" what you want it to do, it just follows your commands blindly.
As an example, let's say you made a mistake and you wrote this:
store 10 in memory at address 1
store 5 in memory at address 5
load the value at address 1 into register A
load the value at address 50 into register B
add B to A and store the result in B
store the result of B in memory at address 2
You may hope the CPU will correct you and use the right address but since it doesn't even check for this, the computer will happily run the code and add whatever was at address 50 to 10. When there's only 3 variables it's pretty easy to keep track but as you can guess, the more variables you add, the more difficult it is to remember what memory address corresponds to what data.
To help with this problem, we could use something like "address labels", basically allowing us to write the above code in this way:
please replace all instances of "number1" with "address 1"
please replace all instances of "number2" with "address 5"
please replace all instances of "result" with "address 2"
store 10 in memory at number1
store 5 in memory at number2
load the value at number1 into register A
load the value at number2 into register B
add B to A and store the result in B
store the result of B in memory at result
This way, there's no risk to use the wrong address! "number1", "number2" and "result" are meant to help the programmer so they doesn't have to remember where variables are but since the computer only understand addresses we would need to use a special software to convert the easier to understand code to instructions the machine would actually be able to run.
As time went by, we started creating more and more tools for humans to be able to write better code faster, the C programming language is one on them. Exactly like the "please replace" example, C code helps you avoid mistakes and simplifies programming a lot, at the cost of not being understood by the computer at all.
That's why you need to use a special software called a compiler to run your code, it takes your code and compiles it into the different instructions your dumb computer will execute blindly.
Through the answer I only used pseudo-code so just to get a glimpse at how things work in the real world, let's use some real C code and real CPU assembler. Here's a really simple C code to add two numbers:
int main()
{
int a = 10;
int b = 5;
int result = a + b;
return result;
}
and here's the x86_64 ASM code my compiler created from it:
pushq %rbp
movq %rsp, %rbp
movl $10, -12(%rbp)
movl $5, -8(%rbp)
movl -12(%rbp), %edx
movl -8(%rbp), %eax
addl %edx, %eax
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
popq %rbp
ret
Note that the ASM listing is still not "raw", it may be a lot more difficult for us to understand than C but it's still too abstract for the CPU.
This minimal program
int r = 100;
return r;
generates just one instruction in main, before the ret:
mov eax,0x64
There is only an immediate and a register. No address. Good nobody asked for it.
With return (long)&r it is (after some stack-checking):
lea eax,[rsp+0x4]
Here there is no value, only the address of where one could (and would) be stored. It's a real living address, but not one containing "100".
Because C's main() returns int, the eax (not rax) is used, and the aligned half of the current stack position (+0x4). The version:
long r = 100;
return &r;
compiles to simply:
mov eax,esp
(i.e. no calculation with lea needed)
To get rid of the different warnings: return (int)(long)&r. This probably shows that addresses are not meant to be returned outside. Here it is only done to force -O3 to do something at all.
So pointers can be created on demand. But in a real program the compiler already has that address stored somewhere / in use.
An infinite pointer "loop" is prevented by:
error: lvalue required as unary '&' operand
6 | return &(&r);
You'd have to put &r into a fresh variable first, before you can take it's address. Fresh variable means new name (or array index) for the programmer and a new memory address ("lvalue") for the compiler.
I finally resolved my confusion(thanks to all the answers) which basically boils down to this.
In real hardware memory, there is a permanent address of each byte of data. At the software level, the operating system creates virtual addresses that map to those real addresses. It's a one-to-one mapping, for one hardware address, there is only one virtual address at a time.
In C, the compiler creates a hashmap-like data structure with variable names as keys and virtual addresses as values. For every new variable, a new entry is added to the hashmap. Whenever we want to get a virtual address of a variable, it's like asking the compiler, "hey, what is the corresponding virtual address associated with this variable name" and the compiler looks through the hashmap and returns the address corresponding to that variable name.
This is just a simplification, as the details are beyond my knowledge, but it nonetheless relieved my confusion for now.

How do I assign an integer value to a pointer in C?

I am creating an emulator for an instruction set architecture, and I needed to implement a stack structure. I decided that my %eip, %ebp and %esp would be int pointers. However, there are situations where I need to store memory addresses on the stack, in which case this memory would be encoded as an integer value. But when I return this value, I need to put it back into my instruction pointer, which is implemented as an int pointer. C will not let me assign my integer to my int pointer, so I have no way of recovering these memory addresses from the "stack". Any suggestions?
To assign an int value to an int * object, use an explicit cast, as in:
destination = (int *) source;
Your question says “C will not let me assign my integer to my int pointer” but fails to state exactly what the problem is. Presumably you are getting some diagnostic message from the compiler. This would be because assigning an int value to an int * object violates the C standard’s constraints for assignments. The code above shows how to work around that.
That solves the immediate problem of the compiler diagnostic. However, there can be various issues with using int values as containers for pointers, including the possibility of trap values and discrepancies between the sizes of pointers and integers. Provided that int and int * are the same size, using an int to hold an int * is not unlikely to work, but you should be sure of the properties of your C implementation.
I decided that my %eip, %ebp and %esp would be int pointers.
This is not a sound architectural decision. You need to reconsider it.
The size of a pointer is architecture-dependent -- in particular, an int * will be 64 bits wide on a 64-bit system. By contrast, all of these registers are 32 bits wide by definition. Using a 64-bit pointer to store their values will result in unexpected behavior.
These registers are not required to be aligned to an integer. In particular, EIP is (at best) aligned to an instruction, and will be incremented by one byte when running 1-byte instructions. Deferencing an int * which is not properly aligned will cause an unaligned access fault on many systems.
There is no hard architectural distinction between any of the integer registers (EA/B/C/DX, ESP, EBP, ESI, EDI). All of them can be referenced in an ModRM encoding, and can be treated as either a numeric value or an address, depending on the context. Singling ESP and EBP out will unnecessarily complicate your emulator, and is likely to create a lot of obnoxious special cases in your code.
Note that, as you are emulating a 32-bit system on what might not be a 32-bit platform, you will need some way of translating addresses within the emulated system to "real" addresses in the host process. There are a number of different ways of doing this; which one is most appropriate for you will depend on your specific goals.
It is implementation defined but if the integer width is not smaller than the pointer - you can use it this way.
Some people say that the using ptrdiff_t and NULL pointer as a reference is more portable and safer.
ptrdiff_t myptrdiff = myptr - (type_of_myptr *)NULL;
myptr = myptrdiff + (type_of_myptr *)NULL;

How to directly access a memory address without using a pointer?

Below is my code.
Please note that I am not running this code on a normal machine, but on an architecture simulator (gem5).
#include <stdio.h>
int main()
{
int *p;
int x;
p = &x;
p[0] = 3;
// *(0xffff) = 6;
return 0;
}
If I uncomment the line, I get a compiler error (which is expected) "indirection requires pointer operand".
Since I am not running it on an actual machine, but on a simulator, I have control over how the hardware behaves, and the address space.
I want to store value 6 in address 0xffff. One way to do this is:
int *p;
p = (int *)0xffff;
p[0] = 6;
Please note that this will not result in a segmentation fault for me, because I am running it on a simulator, and I control the address space.
But, this is an inefficient way, because every time variable 'p' should be accessed, get 0xffff, and then store 6. Accessing variable 'p' even if declared as register, will take 1 cycle which is costly for me in the long run.
Since I know 'p' will always have 0xffff, can't I write something like
*(0xffff) = 3;
How do I allow the compiler to generate this code?
Any pointers will be of help.
I don't know if you can do it without a pointer at all, but if you don't want to declare a pointer on a separate line, you could do this:
*(int*)(0xffff) = 3;
If you are concerned with the extra cycles, you can use some inline assembly. Typically, the MOV instruction (MOV r/m32, imm32) allows you to move the immediate value into the register, or into the address pointed to by the register. If you wish to bypass the use of the register completely, you could use the C6 instruction (from this post).
c6 04 25 0xffff 3
opcode modr/m sib address immediate
Assuming you are using an x86 architecture, you can include that instruction in inline assembly in your source file.

How are C structure members accessed from memory at runtime?

We have a structure in C say
struct info{
int no;
char first_name[20];
char last_name[20];
char status;
}
At runtime when we try to access these members by their name, say info_var.no or info_var.first_name, or we use a pointer to the structure, info_ptr->no or info_ptr->first_name, how are these individual members accessed?
I mean, the structure will be stored as member by member along with some necessary padding, but how does the runtime or maybe the compiler, if replacement happens at compile time, access those individual members by their name?
I know a lot of it is implementation dependent but if anybody could throw some light on any implementation or just give an overview it would be really nice.
In C, the work is done by the compiler. It compiles the data members of the structs to memory offsets and applies them to the base address of the struct.
There is no dynamic lookup for variable names as in e.g Python
Accessing by a pointer or an object makes no difference, actually info_ptr->no is equivalent to (*info_ptr).no.
Actual member access is compiler-specific.
Say you have:
class A
{
public:
char c;
int x;
A() {};
};
The following is the access code:
A a;
004113BE lea ecx,[a]
004113C1 call A::A (4110E1h)
int y = a.x;
004113C6 mov eax,dword ptr [ebp-8]
004113C9 mov dword ptr [y],eax
So the compiler, in this case, generates the binary knowing where x is stored in memory relative to a - that is 8 bytes into the A instance. This is because of padding.
EDIT: I just saw that the question is about C. Regardless, should be the same :).
There is a big difference between accessing a structure directly and via a pointer.
If you access it directly, the code will access the memory address directly, using a simplified assembler syntax, of a fictitious architecture. The examples below access the member status, which is stored at offset 44 in the structure:
MOVB varno+44, reg2
On the other hand, if you would access it via a local pointer, the pointer would typically be stored in a register. So the code would look something like:
MOVB 44[reg1], reg2
The worst scenario is if the pointer itself is a global pointer, then the code must first read the value of the pointer:
MOVL info_ptr, reg1
MOVB 44[reg1], reg2
The compiler can, in some cases, cache the pointer when performing multiple accesses. However, if the accesses are writes (to pointers or to characters), then compiler must assume that the pointer itself might have been changed and thus re-read it from memory.
I would strongly recommend using a one global structure, if your application only contains one.
Each field has a pre-determined offset from the start of the struct. The offset is determined at compile time. The machine code simply adds the field's offset to go from the address of the struct to the address of the field.
When you say "At runtime when we try to access these members by their name", it is important to note that all of the work having to do with the name is done at compile time.

Can I make a pointer to the code, and pass to the next instruction?

Like this link http://gcc.gnu.org/onlinedocs/gcc-3.3.1/gcc/Labels-as-Values.html
I can get the memory address of an label, so if I declare a label, get your address, and add your address, i will pass to next instruction? some ilustration >
int main () {
void *ptr;
label:
instruction 1;
instruction 2;
ptr = &&label;
// So if I do it...
ptr = ptr + 1;
// I will get the instruction 2 correct??
Thanks for all answers.
No, I don't think so.
First of, you seem to take the address of a label, which doesn't work. The label is interpreted by the compiler but it does not represent an actual adress in your code.
Second, every statement in C/C++ (in fact any language) can be translated to many machine language instructions, so instruction 1 could be translated to 3, 5, 10 or even more machine instructions.
Third, your pointer points to void. The C compiler does not know how to increment a void pointer. Normally when you increment a pointer, it adds the size of the data type you are pointing to to the address. So incrementing a long-pointer will add 4 bytes; incrementing a char-pointer will add 1 byte. In this case you have a void-pointer, which points to nothing, and thus cannot be incremented.
Fourth, I don't think that all instructions in x86 machine language are represented by the same number of bytes. So you cannot expect from adding something to a pointer that it gets to the next instruction. You might also end up in the middle of the next instruction.
You can't perform arithmetic on a void*, and the compiler wouldn't know what to add to the pointer to have it point to the next 'instruction' anyway - there is no 1 to 1 correspondence between C statement and the machine code emitted by the compiler. Even for CPUs which have a 'regular' instruction set where instructions are the same size (as opposed to something like the x86 where instructions have a variable number of bytes), a single C statement may result in several CPU instructions (or maybe only one - who knows?).
Expanding on an example in the GCC docs, you might be able to get by with something like the following, but it requires a label for each statement you want to target:
void *statements[] = { &&statement1, &&statement2 };
void** ptr;
statement1:
instruction 1;
statement2:
instruction 2;
ptr = statements;
// goto **ptr; // <== this will jump to 'instruction 1'
// goto **(ptr+1); // <== this will jump to 'instruction 2'
Note that the &&label syntax is described under C Extensions section in GCC docs. It's not C, it's GCC.
Plus, void* does not allow pointer arithmetic - it's a catch-all sort of type in C for pointing at anything. The assumption is that the compiler does not know size of the object it points to (but the programmer should :).
Even more, instruction sizes are widely different on different architectures - four bytes on SPARC, but variable length on x86, for example.
I.e. it doesn't work in C. You will have to use inline assembler for this sort of things.
No, because you can't increment void *.
void fcn() { printf("hello, world\n"); }
int main()
{
void (*pt2Function)() = fcn;
pt2Function(); // calls fcn();
// error C2171: '++' : illegal on operands of type 'void (__cdecl *)(void)'
// ++pt2Function;
return 0;
}
This is VC++, but I suspect gcc is similar.
Edited to add
Just for fun, I tried this—it crashed:
int nGlobal = 0;
__declspec(naked) void fcn()
{
// nop is 1-byte instruction that does nothing
_asm { nop }
++nGlobal;
_asm { ret }
}
int main()
{
void (*pt2Function)() = fcn;
// this works, incrementing nGlobal:
pt2Function();
printf("nGlobal: %d", nGlobal);
char *p = (char *) pt2Function;
++p; // point past the NOP?
pt2Function = (void (*)()) p;
// but this crashes...
pt2Function();
printf("nGlobal: %d", nGlobal);
return 0;
}
It crashed because this line doesn't do what I thought it did:
void (*pt2Function)() = fcn;
I thought it would take the address of the first instruction of fcn(), and put it in pt2Function. That way my ++p would make it point to the second instruction (nop is one byte long).
It doesn't. It puts the address of a jmp instruction (found in a big jump table) into pt2Function. When you increment it by one byte, it points to a meaningless location in the jump table.
I assume this is implementation-specific.
I would say "probably not". The value of the pointer will be right, because the compiler knows, but I doubt that the + 1 will know the length of instructions.
Let us suppose there's a way to get the address of a label (that is no an extension of a specific compiler). Then the problem would really be "the next instruction" idea: it can be very hard to know which is the next instruction. It depends on the processor, and on processors like x86 to know the length of an instruction you have to decode it, not fully of course but it is anyway some complex job... on notable RISC architectures, instructions' length is a lot easier and getting the next instruction could be as easy as incrementing the address by 4. But there's no a general way to do it at runtime, while at compile time it could be easier, but to allow it in a C-coherent way, C should have the type "instruction", so that "instruction *" can be a pointer to an instruction, and incrementing such a pointer would point correctly to the next instruction, provided the code is known at compile time (so, such a pointer can't point really to everything pointer can point to in general). At compile time the compiler could implement this feature easily adding another "label" just beyond the generated instruction pointed by the "first" "label". But it would be cheating...
Moreover, let us suppose you get the address of a C label, or C function, or whatever. If you skip the first instruction, likely you won't be able to "use" that address to execute the code (less the first instruction), since without that single instruction the code may become buggy... unless you know for sure you can skip that single instruction and obtain what you want, but you can't be sure... unless you take a look at the code (which can be different from compiler to compiler), and then all the point of doing such a thing from C disappears.
So, briefly, the answer is no, you can't compute the pointer to the next instruction; and if you do someway, the fact that you're pointing to code becomes meaningless since you can't jump to that address and be sure of the final behaviour.

Resources