memset() trouble

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Shvets04
Member
Member
Posts: 28
Joined: Wed Feb 13, 2019 3:07 pm

memset() trouble

Post by Shvets04 »

I have the function:

Code: Select all

ordered_array_t place_ordered_array(void *addr, u32int max_size, lessthan_predicate_t less_than)
{
    ordered_array_t to_ret;
    to_ret.array = (type_t*)addr;
    memset(to_ret.array, 0, max_size*sizeof(type_t));
    to_ret.size = 0;
    to_ret.max_size = max_size;
    to_ret.less_than = less_than;
    return to_ret;
}
The code doesn't execute after memset().
addr = 0xc000,
max_size*sizeof(type_t) is around 500 000.

The function is called by this, that is called by this, that is called in the kernel.

memset() source.

How to fix if?
nullplan
Member
Member
Posts: 1801
Joined: Wed Aug 30, 2017 8:24 am

Re: memset() trouble

Post by nullplan »

Well, what does happen? Have you asked a debugger? Is it possible the memset just takes a while?

The code looks reasonable enough, except of course for the fact that you don't have the four mem* functions GCC requires even in freestanding mode. You must have an implementation of memset(), memcpy(), memcmp(), and memmove(). You only have memory_set(), which isn't the same.

Here is my compiler support library. In case it actually is creative enough to even get a copyright, it is hereby released into the public domain. Optimization is left as an excercise to the reader, if need be. Oh yeah, and it is C, at least C99, and won't work as C++.

Code: Select all

#include <stddef.h>

void *memcpy(void* restrict a, const void *restrict b, size_t len) {
    unsigned char *d = a;
    const unsigned char *s = b;

    if (d != s) {
        while (len--)
            *d++ = *s++;
    }
    return a;
}

void *memmove(void* a, const void* b, size_t len) {
    unsigned char *d = a;
    const unsigned char *s = b;
    if (d <= s || d >= s + len)
        return memcpy(d, s, len);
    d += len;
    s += len;
    while (len--)
        *--d = *--s;
    return a;
}

void *memset(void *a, int v, size_t len) {
    unsigned char *d = a;
    while (len--)
        *d++ = v;
    return a;
}

int memcmp(const void * restrict a, const void * restrict b, size_t len) {
    int r = 0;
    const unsigned char *x = a;
    const unsigned char *y = b;

    while (len--) {
        r = *x - *y;
        if (r)
            return r;
        x++, y++;
    }
    return 0;
}
Carpe diem!
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: memset() trouble

Post by bzt »

nullplan wrote:Well, what does happen? Have you asked a debugger? Is it possible the memset just takes a while?
Yeah that would be nice to know.
The code looks reasonable enough, except of course for the fact that you don't have the four mem* functions GCC requires even in freestanding mode. You must have an implementation of memset(), memcpy(), memcmp(), and memmove(). You only have memory_set(), which isn't the same.
That's not entirely true. First without a memset() implementation the code wouldn't compile and link in the first place. Second, gcc has a dirty, totally libgcc independent hack for the mem functions (which works in freestanding mode too), it includes the __builtin_memset() in the final executable if memset() implementation otherwise not found. This is highly non-standard, and for example Clang doesn't do it.
The ISO C90 functions abort, abs, acos, asin, atan2, atan, calloc, ceil, cosh, cos, exit, exp, fabs, floor, fmod, fprintf, fputs, frexp, fscanf, isalnum, isalpha, iscntrl, isdigit, isgraph, islower, isprint, ispunct, isspace, isupper, isxdigit, tolower, toupper, labs, ldexp, log10, log, malloc, memchr, memcmp, memcpy, memset, modf, pow, printf, putchar, puts, scanf, sinh, sin, snprintf, sprintf, sqrt, sscanf, strcat, strchr, strcmp, strcpy, strcspn, strlen, strncat, strncmp, strncpy, strpbrk, strrchr, strspn, strstr, tanh, tan, vfprintf, vprintf and vsprintf are all recognized as built-in functions unless -fno-builtin is specified (or -fno-builtin-function is specified for an individual function). All of these functions have corresponding versions prefixed with __builtin_.
Cheers,
bzt
Octocontrabass
Member
Member
Posts: 5586
Joined: Mon Mar 25, 2013 7:01 pm

Re: memset() trouble

Post by Octocontrabass »

bzt wrote:That's not entirely true. First without a memset() implementation the code wouldn't compile and link in the first place. Second, gcc has a dirty, totally libgcc independent hack for the mem functions (which works in freestanding mode too), it includes the __builtin_memset() in the final executable if memset() implementation otherwise not found. This is highly non-standard, and for example Clang doesn't do it.
I don't see where you're getting that from the documentation. The __builtin_memset() function doesn't exist, it's just an optimizer hint that allows GCC to choose either a memset() function reference or equivalent inline code. It's the same for all of the builtin functions.

The special case for memcpy, memmove, memset and memcmp in freestanding mode is due to GCC's optimizer. If you write code that's equivalent to one of those four functions, GCC will optimize it into the equivalent builtin function, and the builtin function may translate to a function call.
Shvets04
Member
Member
Posts: 28
Joined: Wed Feb 13, 2019 3:07 pm

Re: memset() trouble

Post by Shvets04 »

nullplan wrote:Well, what does happen? Have you asked a debugger? Is it possible the memset just takes a while?

The code looks reasonable enough, except of course for the fact that you don't have the four mem* functions GCC requires even in freestanding mode. You must have an implementation of memset(), memcpy(), memcmp(), and memmove(). You only have memory_set(), which isn't the same.

Here is my compiler support library. In case it actually is creative enough to even get a copyright, it is hereby released into the public domain. Optimization is left as an excercise to the reader, if need be. Oh yeah, and it is C, at least C99, and won't work as C++.

Code: Select all

#include <stddef.h>

void *memcpy(void* restrict a, const void *restrict b, size_t len) {
    unsigned char *d = a;
    const unsigned char *s = b;

    if (d != s) {
        while (len--)
            *d++ = *s++;
    }
    return a;
}

void *memmove(void* a, const void* b, size_t len) {
    unsigned char *d = a;
    const unsigned char *s = b;
    if (d <= s || d >= s + len)
        return memcpy(d, s, len);
    d += len;
    s += len;
    while (len--)
        *--d = *--s;
    return a;
}

void *memset(void *a, int v, size_t len) {
    unsigned char *d = a;
    while (len--)
        *d++ = v;
    return a;
}

int memcmp(const void * restrict a, const void * restrict b, size_t len) {
    int r = 0;
    const unsigned char *x = a;
    const unsigned char *y = b;

    while (len--) {
        r = *x - *y;
        if (r)
            return r;
        x++, y++;
    }
    return 0;
}
What information you want to get from debuger?

The code from initialise_pagint()

Code: Select all

 // Now, enable paging!
    switch_page_directory(kernel_directory);
    print_s("test");
    // Initialise the kernel heap.
    kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0);
    print_s("testFInal");
}
"test" is being print, but "testFinal" not.
nullplan
Member
Member
Posts: 1801
Joined: Wed Aug 30, 2017 8:24 am

Re: memset() trouble

Post by nullplan »

Shvets04 wrote:What information you want to get from debuger?

The code from initialise_pagint()

Code: Select all

 // Now, enable paging!
    switch_page_directory(kernel_directory);
    print_s("test");
    // Initialise the kernel heap.
    kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0);
    print_s("testFInal");
}
"test" is being print, but "testFinal" not.
Again: What does happen? That's the question you should be asking yourself. Run the code and when you think it's hanging, break into the debugger and see where you are, and why you are in an infinite loop.
Carpe diem!
bigboyav
Posts: 10
Joined: Sat Dec 29, 2018 3:09 am

Re: memset() trouble

Post by bigboyav »

If something is breaking I would look at the size parameter you pass to memset().
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: memset() trouble

Post by bzt »

Octocontrabass wrote:I don't see where you're getting that from the documentation. The __builtin_memset() function doesn't exist
Read the documentation more carefully. I've linked it and also quoted from the doc, but let's quote that part again:
gcc manual wrote:...memset,...
All of these functions have corresponding versions prefixed with __builtin_.
If you still have doubt, check out the source: https://github.com/gcc-mirror/gcc/blob/ ... builtins.c. There's no point in denying the obvious.

To the OP: we still don't know what happens, and what arguments you pass to memset. We can't help without those. A debugger can tell you the actual parameters used.

Cheers,
bzt
Korona
Member
Member
Posts: 1000
Joined: Thu May 17, 2007 1:27 pm
Contact:

Re: memset() trouble

Post by Korona »

Everything that nullplan and Octocontrabass said is entirely correct. __builtin_memset() still calls into the memset symbol in many situations, regardless of whether __builtin_memset is used or not. This behavior is consistent with Clang. Indeed, it really works the other way around: When GCC sees a call to memset() (or any of the other builtins) in your code, it internally replaces the call by __builtin_memset() (which is a keyword, not a function!). It then applies optimizations and tries to elide the builtin. If that does not work, it does generate a call to the memset symbol (this is documented on the page that bzt cited: "Many of these functions are only optimized in certain cases; if they are not optimized in a particular case, a call to the library function is emitted."). For example, this can be verified by compiling sin(constant): GCC will just replace the call by its result at compile time.

In the case of the snippet above, this behavior can be avoided with -fno-builtin (which is implied by -ffreestanding), but you cannot rely on this fact for the mem* functions, as documented by the GCC manual: "Most of the compiler support routines used by GCC are present in libgcc, but there are a few exceptions. GCC requires the freestanding environment provide memcpy, memmove, memset and memcmp. Finally, if __builtin_trap is used, and the target does not implement the trap pattern, then GCC emits a call to abort." Note that still is still independent on whether you write __builtin_memset() or memset() in your source. All that -fno-builtin does is making the memset not degrade into __builtin_memset automatically. This can be seen from this snippet, which uses __builtin_memset if you drop the -fno-builtin.

Thus, I suspect the OP's issue is the one that nullplan brought up -- you need to have a memset() symbol that does the right thing, otherwise, you're breaking GCC's expectations.
managarm: Microkernel-based OS capable of running a Wayland desktop (Discord: https://discord.gg/7WB6Ur3). My OS-dev projects: [mlibc: Portable C library for managarm, qword, Linux, Sigma, ...] [LAI: AML interpreter] [xbstrap: Build system for OS distributions].
Post Reply