Hi, I need urgent help with a Univ assignment today. I have only a simple question: how do I allocate memory using only syscalls (that is, without linking to the C standard library and calling malloc)?

I'm porting a Windows assembly program to Linux, all I have left are a bunch of LocalAlloc calls that I don't know how to translate. :(
Posted on 2005-05-18 14:24:37 by QvasiModo
You could either use brk or mmap/munmap/mremap.
brk simply enlarges current process`s heap. First get current top of the bss section (call brk with null in ebx)
Than add to the result new desired limit and execute brk once again.

mov eax, 45
xor ebx, ebx ; current top of the bss section will be returned in eax
int 80h

mov eax, 45
mov ebx, new limit
int 80h


With mmap you could allocate pages directly. Sorry I can't recall what parameter goes in which register. But usage of this syscall is pretty straightforward. Specify MAP_ANONYMOUS flag and set file descriptor parameter to -1.
Posted on 2005-05-18 15:20:59 by arafel
The brk approach seems cleaner, but I'll go for mmap/munmap just because it's simpler...

Thanks! I was really lost with this one... :)
Posted on 2005-05-18 16:34:28 by QvasiModo
Does this make sense?

I assumed that mmap would return a pointer on success, or -1 on failure. I'm passing the pointer to a mmap_args_struct with all zeroes, except for the flags (MAP_ANONYMOUS), llen (the amount of bytes to allocate) and fd (-1). Also I'm using the first DWORD to store the memory allocated.

Here's the code:


;-----------------------------------------------------------------------------
; Allocates memory.
; Uses stdcall convention.
malloc: push    ebp
        mov    ebp,    esp
        sub    esp,    4 * 6

        ; Stack frame:
        ;          unsigned long addr      \
        ;          unsigned long len      |
        ;          unsigned long prot      | struct mmap_arg_struct
        ;          unsigned long flags    |
        ;          unsigned long fd        |
        ;          unsigned long offset    /
        ;          EBP.
        ;          Return address.
        ;          Amount of bytes to alloc.

        mov    dword  , 0
        mov    eax,   
        add    eax,    000001000h + 4
        and    eax,    0FFFFF000h
        mov    , eax
        mov    dword  , 0
        mov    dword  , 800h      ; MAP_ANONYMOUS
        mov    dword  , -1
        mov    dword  , 0
        mov    eax,    90
        lea    ebx,   
        xor    ecx,    ecx
        xor    edx,    edx
        int    80h
        test    eax,    eax
        jns    .ok
        xor    eax,    eax
        jmp    .listo
.ok:    mov    ecx,                ; Keep size in the first DWORD...
        mov    ,  ecx
        add    eax,    4                      ; ...and return ptr to second DWORD.
.listo: leave
        retn    4


;-----------------------------------------------------------------------------
; Frees the memory.
; Uses stdcall convention.
mfree:
        ; Stack frame:
        ;          Return address.
        ;          Pointer to allocated memory.

        mov    ebx,                ; Pointer to second DWORD.
        mov    ecx,                  ; Size is on the first.
        mov    eax,    91
        sub    ebx,    4                      ; Pointer to first DWORD.
        int    80h
        retn    4
Posted on 2005-05-18 16:47:15 by QvasiModo
Oh i forgot about mandatory flags. MAP_PRIVATE must be specified along MAP_ANONYMOUS.
Also protection must be one or combination of PROT_READ,?PROT_WRITE,?PROT_EXEC.
Posted on 2005-05-18 17:31:49 by arafel
By the way MAP_ANONYMOUS in mine sys/mman.h defined as 20h. (kernel 2.6)
Posted on 2005-05-18 17:53:40 by arafel
Ok, been reading the HLA standard library, I think I fixed it. Too bad I don't have a Linux box to test it! :(
Posted on 2005-05-18 18:14:28 by QvasiModo
Why not just link against libc? :)
Posted on 2005-05-19 07:44:43 by f0dder
isn't it will break the whole point of writing something in assembly?
Posted on 2005-05-19 09:07:28 by arafel
Not really, IMHO - libc is always available on *u*x operating systems, it's kind of the API there... since those platforms also tend to support dynamic linking most of the time, it isn't a problem linking to libc.
Posted on 2005-05-19 11:00:04 by f0dder
I meant it in a sense that linking something that initially was supposed to be written with optimization in mind (hence written in asm) to hll libraries is a kind of perversion? :D.
But anyway it's only my opinion. Of course you are right that dynamic linking to libc could be much more convenient on most cases.
Posted on 2005-05-19 11:18:01 by arafel
f0dder is being quite modest in his suggestion, Linux without LIBC simply isn't Linux. However, you should study how LIBC interacts with the kernel to help further your understanding, LIBC isn't the only way... it is just the most accepted way.
Posted on 2005-05-19 11:22:09 by SpooK
Well, if you don't want to use LIBC, you should come up with something that's better than linking against libc; na?ve schemes based on (s)brk and mmap aren't... you need to put quite some work into the memory manager (ie: allocate big chunk, manage big chunk *efficiently*).
Posted on 2005-05-19 11:28:03 by f0dder
I agree that using libc is the logical approach. But it's an assignment for the Univ, so it's only supposed to be educational - no one said it also had to make sense. ;)
Posted on 2005-05-19 14:59:06 by QvasiModo