LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-14-2014, 01:32 PM   #1
prushik
Member
 
Registered: Mar 2009
Location: Pennsylvania
Distribution: gentoo
Posts: 372

Rep: Reputation: 29
mmap() syscall on x86_64


Hi everybody.
This might seem a strange question, but I have 2 lines of code that I expect to do the exact same thing. The trouble is, only one of them works.

Here's the working code:
Code:
fbp = (uint8_t *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
And the non-working code:
Code:
fbp = (uint8_t *)syscall(SYS_mmap, 0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
This is running on Linux x86_64, and I tried with both Musl and glibc, as well as my own assembly routine. I think the Linux x86_64 calling convention should pass the arguments like this, but it doesn't work. I looked at both musl source and glibc source, and both seem to say I'm not doing anything wrong.
The mmap2 syscall seems to not be available on x86_64 machines, so I do not think I should be using that instead. But I am doing something wrong and I am just not smart enough to spot it.

Can anybody spot my mistake? Thanks!
 
Old 04-14-2014, 01:55 PM   #2
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
The mmap2 syscall seems to not be available on x86_64 machines, so I do not think I should be using that instead.
Did you try it? The manpage says different:

Quote:
Originally Posted by man 2 mmap
Originally, this function invoked a system call of the same name. Since kernel 2.4, that system call has been superseded by mmap2(2), and nowadays the glibc mmap() wrapper function invokes mmap2(2) with a suitably adjusted value for offset.
 
Old 04-14-2014, 10:32 PM   #3
prushik
Member
 
Registered: Mar 2009
Location: Pennsylvania
Distribution: gentoo
Posts: 372

Original Poster
Rep: Reputation: 29
Quote:
Originally Posted by ntubski View Post
Did you try it? The manpage says different:
Yep,

mmap2 function:
Code:
/tmp/cc4HPBOs.o: In function `main':
fblog.c:(.text+0x159): undefined reference to `mmap2'
collect2: error: ld returned 1 exit status
SYS_mmap2 syscall:
Code:
./fblog.c:44:29: error: ‘SYS_mmap2’ undeclared (first use in this function)
  fbp = (uint8_t *)__syscall(SYS_mmap2, 0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
Also, I can see in /usr/include/bits/syscall.h that SYS_mmap2 is defined only if WORDSIZE is 32.
Seems like the manpage is correct for 32 bit machines only.
 
Old 04-15-2014, 10:31 AM   #4
prushik
Member
 
Registered: Mar 2009
Location: Pennsylvania
Distribution: gentoo
Posts: 372

Original Poster
Rep: Reputation: 29
I tried a few more things and discovered something interesting. The code works fine with the musl c library. Do you think it's possible that I have located a bug in glibc?
I can't imagine how that could be since syscall() gets used internally in glibc for almost every function, how could that function have a bug like this?
But if there is no bug and my code is the problem, why does it work fine with musl libc?
 
Old 04-15-2014, 07:00 PM   #5
blip
LQ Newbie
 
Registered: Aug 2013
Posts: 17

Rep: Reputation: Disabled
Be careful passing NULL pointers as bare 0's. NULL is often #defined as (void *)0 and it is 64 bits wide on your platform whereas a bare 0 is a 32-bit integer. When passing parameters to variadic functions, as there is no strict function definition, the compiler's only cue to argument type and size is what you give it.

Your syscall() invocation passes the first argument to mmap() as a 32-bit integer, not a pointer as you expected. The final argument to mmap() probably should be cast to off_t in case it's 64-bit, too.
 
1 members found this post helpful.
Old 04-15-2014, 10:44 PM   #6
prushik
Member
 
Registered: Mar 2009
Location: Pennsylvania
Distribution: gentoo
Posts: 372

Original Poster
Rep: Reputation: 29
Quote:
Originally Posted by blip View Post
Be careful passing NULL pointers as bare 0's. NULL is often #defined as (void *)0 and it is 64 bits wide on your platform whereas a bare 0 is a 32-bit integer. When passing parameters to variadic functions, as there is no strict function definition, the compiler's only cue to argument type and size is what you give it.

Your syscall() invocation passes the first argument to mmap() as a 32-bit integer, not a pointer as you expected. The final argument to mmap() probably should be cast to off_t in case it's 64-bit, too.
Ahh, thats wonderful. totally my mistake, I made the assumption that ints and pointers and off_ts should be the same size. Silly me. I have it working now with glibc at least. Now I just have to debug my assembly code and everything will be perfect.

Thanks!
 
Old 04-16-2014, 03:06 AM   #7
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,862
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
Well, on CPU-level, function-parameters are always word-sized (either in registers or stack-levels), so in 64-bit environment, passing a 64-bit value to a 32-bit parameter should be okay; on the other hand, a 32-bit value cannot be passed to a 64-bit parameter without type-cast, because the upper 32-bit might contain random garbage (this is the case on x86_64 platform).

Edit:
Correction:
old: function-parameters are always word-sized
new: function-parameters are always word-sized, or the multiple of that, eg: int64_t in 32-bit environment takes two stack-levels

Last edited by NevemTeve; 04-16-2014 at 03:09 AM.
 
  


Reply

Tags
amd64, linux, mmap, syscall, x86_64



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Modifying syscall.c HSN Programming 3 09-24-2009 09:52 PM
vfork syscall bandaru_sivakrishna Linux - Software 3 07-13-2009 11:21 PM
ipm timed out error on Red Hat 2.6.9-67.0.22.ELsmp #1 SMP x86_64 x86_64 x86_64 GNU/L bellnarm Linux - Newbie 0 07-07-2009 04:36 PM
i need help in understanding syscall tonyr81 Linux - Kernel 4 05-27-2008 05:18 PM
how to use kill syscall shifter Programming 19 05-28-2007 10:04 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 11:19 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration