I tried using mmap like this:
off_t offset = 0x123456789;
long pagesize = sysconf(_SC_PAGE_SIZE);
int pageoffset = offset % pagesize;
//Open file, get file descriptor
fd = open("./test", O_RDONLY);
map_main = mmap(NULL, 106 + pageoffset, PROT_READ | PROT_EXEC,
MAP_SHARED, fd, offset - pageoffset);
Not behaving as expected.
Am I doing right, for reading file from specific location?
Reference: Segfault while using mmap in C for reading binary files
Related
uint8_t *out = mmap(NULL, OUT_SIZE, MAP_ANON, PROT_READ | PROT_WRITE, -1, 0);
I am running this line on an ARM64 Macbook and I keep getting Bad file descriptor. I am not trying to map a file, so how do I fix this?
You appear to have reversed the prot argument with the flags argument. It is plausible that as a result, mmap() thinks you are trying to map a real file, and therefore expects the given file descriptor to be valid. Of course, -1 is not a valid file descriptor.
It looks like the call you wanted would be:
uint8_t *out = mmap(NULL, OUT_SIZE, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
Note: it occurs to me that detecting this kind of error is a good reason for the convention (or requirement, in some implementations) that the file descriptor be specified as -1 for an anonymous mapping.
I'm using a queue created with a circle buffer in C by mapping a file to two halves of the same underlying buffer, one after the other. If I attempt to access the buffer immediately after creating it (both before and after mapping the file on top), a bus error is thrown.
I'm programming on a x86 machine, so (if I understand correctly), the only reason this would occur is if the memory location is physically inaccessible. If this is the case, why would mmap return a physically unavailable address?
My code for creating a new code can be seen below.
struct queue create_queue() {
size_t pagesize = getpagesize();
size_t sz = ((BUFFSIZE*sizeof(char *))/pagesize)*(pagesize+1); //align to page
int fd = fileno(tmpfile());
void *buffer = mmap(NULL, 2*sz, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
mmap(buffer, sz, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED, fd, 0);
mmap(buffer+sz, sz, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED, fd, 0);
struct queue new_queue;
new_queue.buffer = (char **)buffer;
new_queue.front = 0;
new_queue.back = 0;
sem_init(&(new_queue.sem), 0, 0);
return new_queue;
}
The problem is that:
size_t sz = ((BUFFSIZE*sizeof(char *))/pagesize)*(pagesize+1); //align to page
does set sz to a multiple of the page size, but to a muiliple of the page size plus one. An alternative approach is:
size_t sz = ((BUFFSIZE*sizeof(char *)+pagesize-1)/pagesize)*pagesize; //align to page
i can check entry point of my binary with "$readelf cbinary -a" and through the code. But how to check its entry point virtual adr when binary is mmaped and then jump there?
int fd;
int PageSize;
char *fileName = "/home/dssiam/workspace_eclipse/hello/src/cprog";
if ((PageSize = sysconf(_SC_PAGE_SIZE)) < 0) {
perror("sysconf() Error=");
}
if ((fd = open(fileName, O_RDWR, S_IXUSR | S_IXGRP | S_IXOTH)) == -1)
{
perror("err open file:");
exit(1);
}
else
{
fd = open(fileName, O_RDWR, S_IXUSR | S_IXGRP | S_IXOTH);
}
void *address;
int len;
off_t my_offset = 0;
len = PageSize*3; //Map one page
address = mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, my_offset);
if (address == MAP_FAILED)
{
perror("mmap error. ");
}
lseek(fd, 24, SEEK_SET);
unsigned long entry_point;
read(fd, &entry_point, sizeof(entry_point)); //IT RETURN entry point adr of my binary at "/home/dssiam/workspace_eclipse/hello/src/cprog" but not in VM
printf("entry: 0x%lx\n", entry_point);
close(fd);
void *ptr = (void *)0x80484b0; // 0x80484b0 - entry_point vaddress
goto *ptr; //no jump here
so i can jump to the start of my main program, but i cant jump to the binary "cprog" stored at my hdd and mmaped region too.
any help would be appreciated.
The code has lots of mistakes (wrong mmap protection, wrong mmap start address, arbitrary pagesize, C standard specifically prohibits this kind of computed goto) but the biggest problem is that this method simply will not work, except maybe for the most basic cases.
You cannot just mmap a single function from elf file into the memory and expect it to work -- you will need to perform relocations for relocatable code, and even for PIC (position independent code), you still need to create GOT.
I am going to guess that what you really want to dynamically load complied files, so use a standard way to do this: compile your file into .so dynamic library, then use dlopen/dlsym to access functions from the file.
I have a simple program going this:
int main(void) {
int fd;
const char *text = "This is a test";
fd = open("/tmp/msyncTest", (O_CREAT | O_TRUNC | O_RDWR), (S_IRWXU | S_IRWXG | S_IRWXO) );
if ( fd < 0 ) {
perror("open() error");
return fd;
}
/* mmap the file. */
void *address;
off_t my_offset = 0;
address = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED, fd, my_offset);
if ( address == MAP_FAILED ) {
perror("mmap error. " );
return -1;
}
/* Move some data into the file using memory map. */
strcpy( (char *)address, text);
/* use msync to write changes to disk. */
if ( msync( address, 4096 , MS_SYNC ) < 0 ) {
perror("msync failed with error:");
return -1;
}
else {
printf("%s","msync completed successfully.");
}
close(fd);
unlink("/tmp/msyncTest");
}
Anything wrong with my code? I have made some simple tests and it seems that the problem comes from strcpy. But according to the definition, I see no problem.
If
fd = open("/tmp/msyncTest", (O_CREAT | O_TRUNC | O_RDWR), (S_IRWXU | S_IRWXG | S_IRWXO) );
is successful, fd will refer to a zero-length file (O_TRUNC). The call to mmap()
address = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED, fd, my_offset);
establishes a memory-mapping, but the pages do not correspond to an object.
http://pubs.opengroup.org/onlinepubs/7908799/xsh/mmap.html has the following to say about this situation:
The system always zero-fills any partial page at the end of an object. Further, the system never writes out any modified portions of the last page of an object that are beyond its end. References within the address range starting at pa and continuing for len bytes to whole pages following the end of an object result in delivery of a SIGBUS signal.
Similarly, man mmap on Linux notes
Use of a mapped region can result in these signals:[...] SIGBUS Attempted access to a portion of the buffer that does not correspond to the file (for example, beyond the end of the file, including the case where another process has truncated the file).
Consequently, you must ftruncate() the file to a non-zero length before mmap()ing it (unless you are mmap()ing anonymous memory).
So I am trying to port some code from Linux to Mac OSX. During porting I came across this code.
static void allocZeroMap(unsigned long size, int prot, const char *name)
{
struct map *newnode;
int fd;
char buf[11];
fd = open("/dev/zero", O_RDWR);
if (fd == -1) {
printf("couldn't open /dev/zero\n");
exit(EXIT_FAILURE);
}
newnode = zmalloc(sizeof(struct map));
newnode->name = strdup(name);
newnode->size = size;
newnode->prot = prot;
newnode->type = INITIAL_MAP;
newnode->ptr = mmap(NULL, size, prot, MAP_ANONYMOUS | MAP_SHARED, fd, 0);
if (newnode->ptr == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
newnode->name = zmalloc(80);
sprintf(newnode->name, "anon(%s)", name);
num_initial_mappings++;
list_add_tail(&newnode->list, &initial_mappings->list);
sizeUnit(size, buf);
printf("mapping[%d]: (zeropage %s) %p (%s)\n",
num_initial_mappings - 1, name, newnode->ptr, buf);
close(fd);
}
So I figured that I would need to just switch newnode->ptr = mmap(NULL, size, prot, MAP_ANONYMOUS | MAP_SHARED, fd, 0); to newnode->ptr = mmap(NULL, size, prot, MAP_ANON | MAP_SHARED, fd, 0); because Mac OSX does not have the MAP_ANONYMOUS flag and uses MAP_ANON instead.
But when I run the program, that mmap call fails with Invalid argument. So my next thought was check the man page for what causes Invalid arguments errors. The first cause is that MAP_FIXED is set and the addr argument is not page aligned, but I'm not calling MAP_FIXED. Second it's says it will return Invalid argument if you don't specify either MAP_PRIVATE or MAP_SHARED but I'm using MAP_SHARED so that shouldn't be it. Next it says the len argument must not be negative, so I printed the size variable and ran it and it's a positive value. The final reason is that the offset argument is not page aligned, but I am passing zero so that shouldn't be the problem either.
So next I checked stack overflow and saw this question mmap with /dev/zero . I tried using MAP_FILE instead of MAP_ANON but now I get Operation not supported by device, which the man page says means I am missing MAP_ANON. So I tried adding MAP_ANON so that I have mmap(NULL, size, prot, MAP_FILE | MAP_ANON| MAP_SHARED, fd, 0); but that returns Invalid argument as well.
So how do I mmap /dev/zero on Mac OSX or at least create a zero-filled memory map on Mac OSX?
You should pass -1 instead of fd as the value of the file descriptor as per mmap() man page. Also as you said MAP_ANON is the correct option for MacOS (at least older versions) and there is not need for MAP_FILE.