-1

I am writing a 64-bit application in C (with GCC) and NASM under Linux.

Is there a way to specify, where I want my heap and stack to be located. Specifically, I want all my malloc'ed data to be anywhere in range 0x00000000-0x7FFFFFFF. This can be done at either compile time, linking or runtime, via C code or otherwise. It doesn't matter.

If this is not possible, please explain, why.

P.S. For those interested, what the heck I am doing:

The program I am working on is written in C. During runtime it generates NASM code, compiles it and dynamically links to the already running program. This is needed for extreme optimization, because that code will be run thousands-if-not-billions of times, and is not known at compile time. So the reason I need 0x00000000-0x7FFFFFFF addresses is because they fit in immediates in assembler code. If I don't need to load the addresses separately, I can just about half the number of memory accesses needed and increase locality.

RuRo
  • 311
  • 4
  • 17
  • 2
    Out of curiosity: why do you want this? –  Aug 03 '17 at 05:11
  • On Windows you can use the [RtlCreateHeap](https://msdn.microsoft.com/en-us/library/windows/hardware/ff552159(v=vs.85).aspx) and family of functions. On Linux you might have to use third party implementations of allocators. – Ajay Brahmakshatriya Aug 03 '17 at 05:18
  • If your allocations are small and few you can just use a "bump allocator". – Ajay Brahmakshatriya Aug 03 '17 at 05:19
  • @AjayBrahmakshatriya the problem is not in memory management, but in allocation. If I can claim a segment of Virtual memory as my own, I can figure out a way to manage it myself. – RuRo Aug 03 '17 at 05:34
  • In the world of statically linked embedded applications, this is daily business, not only to get memory mapped peripherals right. But you probably are aware of that and/or do not care, because it is out of your scope. – Yunnosch Aug 03 '17 at 05:38
  • @Yunnosch It's similar to that but not quite. I want real(tm) physical memory to be allocated and then map it to a virtual address I specify. Something like `mmap`, but with ram instead of a file. – RuRo Aug 03 '17 at 05:44
  • 1
    Do you really need absolute immediates? I read your invisible PS and I am thinking of studying the usually wide choice of address modes. Isn't one available which does "immediate+offset", where offset is in a register, gets configured once and then used with the same number of clocks and bytes as using an absolute immediate? – Yunnosch Aug 03 '17 at 05:44
  • Desiring physical memory is a new aspect I don't see/understand reason for that in your PS. (By the way, in my opinion your PS is not so scary as to hide it... ;-) ) – Yunnosch Aug 03 '17 at 05:46
  • @Yunnosch well, since normal 64 bit addresses don't fit into immediates, I have to load them into a register, which is an extra instruction. You might think that it's not important, but that practically doubles the number of instructions. – RuRo Aug 03 '17 at 05:49
  • 1
    @RuRo if you only want to claim some Virtual Address you can take a look at [mmap](http://man7.org/linux/man-pages/man2/mmap.2.html). WIth `MAP_ANONYMOUS` you should get the addresses. Though I am not you can use it on the address ranges you specified. The kernel *might* be mapped there. If you are flexible about addresses, use some higher ranges. – Ajay Brahmakshatriya Aug 03 '17 at 05:49
  • @AjayBrahmakshatriya I have looked at it. Doesn't it require a file descriptor to map into memory? What would the fd of RAM even be? – RuRo Aug 03 '17 at 05:53
  • 1
    There is a difference between on the one hand loading 64bit into a register each time in two steps and using that (as you describe) and on the other hand setting up an offset register **once** (or at least once per change into assembler) and then using that one with a changing immediate many (million) times. The range of the latter is the same as using an absolute immediate, but the "base" is adaptable to whereever you got your memory allocated. – Yunnosch Aug 03 '17 at 05:53
  • @Yunnosch Yes. That is better, however, how would one find the "base" address and guarantee that all the allocated memory is within +-0x7FFFFFFF of that address. Additionally, it will have to be [base + offset + immediate]. – RuRo Aug 03 '17 at 06:00
  • 1
    @RuRo *MAP_ANONYMOUS - The mapping is not backed by any file; its contents are initialized to zero. The fd argument is ignored; however, some implementations require fd to be -1 if MAP_ANONYMOUS* -- This is what the man pages say. You have to pass this in the flags. – Ajay Brahmakshatriya Aug 03 '17 at 06:04
  • 1
    @RuRo I am definitely sure about this. Infact `mmap` is the standard way of getting memory. All your heap implementations also use this. – Ajay Brahmakshatriya Aug 03 '17 at 06:05
  • @AjayBrahmakshatriya Hmm. I think I misunderstood the docs. If "not backed by any file" means "backed by physical RAM rather than a file", instead of "points to nowhere", then you can write this as an answer, I will accept it. – RuRo Aug 03 '17 at 06:07
  • 1
    The "base + offset" (or whatever the assembler addressing modes offer) would be what malloc() returns. All the malloced memory would be within the range of the size you give as parameter to malloc(). Wouldn't it? – Yunnosch Aug 03 '17 at 06:12
  • 1
    @RuRo mmap always has a RAM. You cannot write directly to disk. Even when you map to fd, you get some physical pages. I will add as an answer. – Ajay Brahmakshatriya Aug 03 '17 at 06:16

1 Answers1

2

For Linux, the standard way of acquiring any Virtual Address range is using the mmap(2) function.

You can specify the starting virtual address and the size. If the address is not already in use and it not reserved by prior calls (or by the kernel) you will get access to the virtual address.

The success of this call can be checked by comparing the return value to the start address you passed. If the call fails, the function returns NULL.

In general mmap is used to map virtual addresses to file descriptors. But this mapping has to happen through physical pages on the RAM. Since the applications cannot directly access the disk.

Since you do not want any file backing, you can use the MAP_ANONYMOUS flag in the mmap call (also pass -1 as the fd).

This is the excerpt for the related part of the man-page -

MAP_ANONYMOUS

The mapping is not backed by any file; its contents are initialized to zero. The fd argument is ignored; however, some implementations require fd to be -1 if MAP_ANONYMOUS (or MAP_ANON) is specified, and portable applications should ensure this. The offset argument should be zero. The use of MAP_ANONYMOUS in conjunction with MAP_SHARED is supported on Linux only since kernel 2.4.

Ajay Brahmakshatriya
  • 8,993
  • 3
  • 26
  • 49