In assembly language we have instructions like:
movl ax, [1000]
This allows us to access specific memory locations.
But in C can we do something similar to this?
I know inline assembly code using asm() will allow you to do this,
but I would like to know about some C specific technique to achieve this.
I tried the following code and got segmentation error:
int *ptr=0xFE1DB124;
*ptr;
This again was confusing as the memory location was identified by the code given below:
int var;
printf("\nThe Address is %x",&var);
So the memory location is available, but I am still getting a segmentation fault.
Why?
Common C compilers will allow you to set a pointer from an integer and to access memory with that, and they will give you the expected results. However, this is an extension beyond the C standard, so you should check your compiler documentation to ensure it supports it. This feature is not uncommonly used in kernel code that must access memory at specific addresses. It is generally not useful in user programs.
As comments have mentioned, one problem you may be having is that your operating system loads programs into a randomized location each time a program is loaded. Therefore, the address you discover on one run will not be the address used in another run. Also, changing the source and recompiling may yield different addresses.
To demonstrate that you can use a pointer to access an address specified numerically, you can retrieve the address and use it within a single program execution:
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
int main(void)
{
// Create an int.
int x = 0;
// Find its address.
char buf[100];
sprintf(buf, "%" PRIuPTR, (uintptr_t) &x);
printf("The address of x is %s.\n", buf);
// Read the address.
uintptr_t u;
sscanf(buf, "%" SCNuPTR, &u);
// Convert the integer value to an address.
int *p = (int *) u;
// Modify the int through the new pointer.
*p = 123;
// Display the int.
printf("x = %d\n", x);
return 0;
}
Obviously, this is not useful in a normal program; it is just a demonstration. You would use this sort of behavior only when you have a special need to access certain addresses.
For accessing Specific memory from user space, we have to map the memory Address to Programs Virtual Address using mmap(), the below C code shows the implementation:
Take a file "test_file" containing "ABCDEFGHIJ".
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
int main(void)
{
char *map_base_addr; // Maping Base address for file
int fd; // File descriptor for open file
int size = 10;
fd= open("test_file", O_RDWR); //open the file for reading and writing
map_base_addr= mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);// Maping file into memory
char *ch= map_base_addr;
int i;
/*Printing first 10 char*/
for(i=0; i<size; i++)
fputc(*(ch+i),stdout);
printf("\n");
*(ch+1) = 'b';
*(ch+4) = 'z';
*(ch+7) = 'x';
/*Printing char after modification*/
for(i=0; i<size; i++)
fputc(*(ch+i),stdout);
printf("\n");
/* Finally unmap the file. This will flush out any changes. */
munmap(map_base_addr, size);
exit(0);
}
The output will be:
ABCDEFGHIJ
AbCDzFGxIJ
It works for me:
#include <stdio.h>
int main(int argc, char**argv) {
int var = 7456;
printf("Adress of var = %x, var=%d\n", &var, var);
int *ptr = (int*)0x22cd28;
printf(" ptr points to %x\n", ptr);
*ptr = 123;
printf("New value of var=%d\n", var);
return 0;
}
Program output:
Adress of var = 22cd28, var=7456
ptr points to 22cd28
New value of var=123
Note:
The address is usually not the same on every execution. When I tried my example I had to run it three times before I got the address to match.
char* can point to any adress (because sizeof (char) = 1). Pointers to larger objects must often be aligned on even adresses (usually one divisible by 4).
Your question doesn't really make much sense if you are running on linux/windows/mac/whatever
http://en.wikipedia.org/wiki/Virtual_memory
You can do that only if you are programming a device without virtual memory, or if you are programming the operating system itself.
Otherwise the addresses you see are not the "real" addresses on the RAM, the operating system translates them to real addresses and if there is not a map to translate your virtual address to a real one, then you can get a segmentation fault. Keep in mind that there are other reasons that can cause a segmentation fault.
Related
I have a function like this
void abc()
{
printf("hello\n");
}
lets suppose I checked and know that the address of above function say 0x08000040 now if I assign it to function pointer in main like this
int main()
{
void (*p)()=(void *)0x08000040;
p();// and call it like
return 0;
}
will it call some how. I tried it does not work but suppose I have function in the same program then will it work after I some how found out the address of the function?
and also is this possible
to assign specific fixed address to some function in current C program
is it possible to export a function address (of abc()) in current program and so other programs can call the function in this program to call above abc() function with address hex values. it happens in kernel with exporting of sys-calls and gdb also does this with trap-handlers. So is there any easy way to make it work.
This works for me:
#include <stdio.h>
#include <stdlib.h>
void abc(void) {
puts("abc");
}
void cba(void) {
puts("cba");
}
int main(void) {
printf("type %p or %p\n", (void*)abc, (void*)cba);
char buf[100];
fgets(buf, sizeof buf, stdin);
long unsigned u = strtoul(buf + 2, NULL, 16); // ignore 0x
void (*p)(void) = (void(*)(void))u; // UB!
p(); // and call it
return 0;
}
The virtual address where a given function is located in memory is entirely implementation defined and further depends on many factors:
it is almost always different for different programs ;
it may change if you modify the program source code and recompile it ;
it may even change each time you execute the same program: modern systems perform address space randomisation in order to reduce vulnerability to certain classes of attacks. The same applies to the stack address.
Do not rely on the address values you observe in the debugger, they are likely to be different the next time you debug the program.
Take this C code for example
#include <stdio.h>
#include <stdlib.h>
int main() {
int x;
int* y = (int *) malloc(10*sizeof(int));
printf("%p\n",&x);
printf("%p\n",y);
printf("%p\n",&(y[1]));
while(1);
return 0;
}
Which will print virtual addresses that look something like this
0x7ffd4e96d214
0x908010
0x908014
The virtual addresses will be different every time you run the binary file which made me think how the virtual address are actually decided for a program ?
This is - probably - the effect of ASLR.
The decision should - as the name Address Space Layout Randomization tells - be random.
I have a simple code:
#include <stdio.h>
#include <stdlib.h>
int main(void){
char *str = (char *) malloc(4*sizeof(char));
int i;
for(i = 0; i < 64; i ++)
printf("%d, %ld, %d, %c\n", i, (long) &(str[i]), (int) str[i], str[i]);
return 0;
}
I allocate a memory into str using malloc() which is available to save 4 letters in str[0], ..., str[3]. I know that malloc() does not initialize its memory while calloc() does.
This program prints str[i] with i, address of str[i], value of str[i], letter of str[i], in order. (I use 64-bits Ubuntu, hence address is long type.)
As expected, addresses are quite different for every time I run the program. But I wonder that why str[24], str[25], and str[26] are -31, 15, 2, repectively, and other values are all 0 as you can see below:
(Note that without option -O0 gives same result.)
How can memory has same sequence (0,0,...,0,-31,15,2,0,0,...) even though only first four 0s in that sequence are allocated and others are out of care?
As you just have pointed out, malloc() doesn't initialize memory (by the way, even if it would, starting from str[4*sizeof(char)] it wouldn't be initialized because it's already out of range).
This means that you print out data that was at this memory location before. It's undefined behaviour so strictly unpredictable.
The fact that you see the same value, could be a coincidence. But if repeatable, and always with the same values, it most probably traces of the what the OS and the standard library did to initialize the environment of your process before giving control to your main().
There is a related SO question about uninitialized variables on stack. The principle of unitialized data giving access to remanent value is similar here, only that it's on the heap.
Here an experiment : a small programme to try to show you the kind of thing that could happen (attention: it's implementation dependent):
int main() {
int i;
// first part ================
char *p=(char*)malloc(100); // allocate a region in memory
for (i=0; i<100; i++) // initialize it to 0
p[i]=0;
strcpy (p+10, "Christophe"); // put some value womewhere in the middle
free(p); // release memory
// second part ============
char *q= (char*)malloc(100); // innocently allocate new memory
// and display its content
printf ("%ld==%ld ? %c%c%c\n", (long) p, (long)q, q[10],q[11], q[12]);
return 0;
}
So you could imagine that something like the first part of this code could be run during the initialization sequence of the standard library (could be at startup of the programme, or the first time you call malloc()).
Here a live demo of this code.
I've just started learning C and I've been running some simple programs using MinGW for Windows to understand how pointers work. I tried the following:
#include <stdio.h>
int main(){
int *ptr;
*ptr = 20;
printf("%d", *ptr);
return 0;
}
which compiled properly but when I run the executable it doesn't work - the value isn't printed to the command line, instead I get an error message that says the .exe file has stopped working.
However when I tried storing the value in an int variable and assign *ptr to the memory address of that variable as shown below:
#include <stdio.h>
int main(){
int *ptr;
int q = 50;
ptr = &q;
printf("%d", *ptr);
return 0;
}
it works fine.
My question is, why am I unable to directly set a literal value to the pointer? I've looked at tutorials online for pointers and most of them do it the same way as the second example.
Any help is appreciated.
The problem is that you're not initializing the pointer. You've created a pointer to "anywhere you want"—which could be the address of some other variable, or the middle of your code, or some memory that isn't mapped at all.
You need to create an int variable somewhere in memory for the int * variable to point at.
Your second example does this, but it does other things that aren't relevant here. Here's the simplest thing you need to do:
int main(){
int variable;
int *ptr = &variable;
*ptr = 20;
printf("%d", *ptr);
return 0;
}
Here, the int variable isn't initialized—but that's fine, because you're just going to replace whatever value was there with 20. The key is that the pointer is initialized to point to the variable. In fact, you could just allocate some raw memory to point to, if you want:
int main(){
void *memory = malloc(sizeof(int));
int *ptr = (int *)memory;
*ptr = 20;
printf("%d", *ptr);
free(memory);
return 0;
}
First Program with comments
#include <stdio.h>
int main(){
int *ptr; //Create a pointer that points to random memory address
*ptr = 20; //Dereference that pointer,
// and assign a value to random memory address.
//Depending on external (not inside your program) state
// this will either crash or SILENTLY CORRUPT another
// data structure in your program.
printf("%d", *ptr); //Print contents of same random memory address
// May or may not crash, depending on who owns this address
return 0;
}
Second Program with comments
#include <stdio.h>
int main(){
int *ptr; //Create pointer to random memory address
int q = 50; //Create local variable with contents int 50
ptr = &q; //Update address targeted by above created pointer to point
// to local variable your program properly created
printf("%d", *ptr); //Happily print the contents of said local variable (q)
return 0;
}
The key is you cannot use a pointer until you know it is assigned to an address that you yourself have managed, either by pointing it at another variable you created or to the result of a malloc call.
Using it before is creating code that depends on uninitialized memory which will at best crash but at worst work sometimes, because the random memory address happens to be inside the memory space your program already owns. God help you if it overwrites a data structure you are using elsewhere in your program.
In the first example, ptr has not been initialized, so it points to an unspecified memory location. When you assign something to this unspecified location, your program blows up.
In the second example, the address is set when you say ptr = &q, so you're OK.
You can set a value for the pointer, but once you've asked for memory for it using "new". This is how your code should look
int main(){
int *ptr;
ptr = new int; //ask for memory
*ptr = 20;
printf("%d", *ptr);
return 0;
}
I have written the following program:
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
void inttobusn(int val, int n, char* bus)
{
int i;
unsigned int digit;
for (i=0; i < n; i++) {
digit = pow(2, (n-1-i));
if (digit <= val) {
val -= digit;
bus[i] = '1';
//printf("hello %c",bus[i]);
} else {
bus[i] = '0';
}
}
}
main(){
char* bus;
inttobusn(37,8,bus);
int i=0;
//printf("%s",bus);
for(i=0;i<12;i++){
printf("%c",bus[i]);
}
}
But on running it doesn't print the elements of the array bus. It doesn't print anything. I am unable to figure out what is wrong. Please could someone point out?
Your code is buggy! you don't allocate memory for the bus[] array, and are trying to access values at garbage location as e.g bus[i] = 0; -- Undefined Behavior in C standard, Undefined means you can't predict how your code will behave at runtime.
This code compiled because syntax-wise the code is correct but at runtime the OS will detect illegal memory access and can terminate your code. (interesting to note: as OS detects memory right violation by a process -- An invalid access to valid memory gives: SIGSEGV And access to an invalid address gives: SIGBUS). In the worst case your program may seem execute without any failure, producing garbage results.
To simply correct it define bus array as char bus[N]; else allocated memory dynamically using void* malloc (size_t size);
Additionally, suggestion to your from #Lochemage and #Ran Eldan:
You need to declare bus with a specific size, like char bus[12]. It has to be at least large enough to fit 12 chars because your for loop at the end is iterating through that many (and you can check your code working with this suggestion #codepade).
Also there is no return type to main() in your code, its should be int main(void).
There is no memory allocated to bus so this is an undefined behavior. Either write
char bus[some sufficient size];
or use malloc, realloc to reserve memory.
You didn't initialize you bus variable.
char* bus = malloc(8 * sizeof(char));