Page 1 of 1

(solved) Help with __translate_amiga_to_unix_path_name

Posted: Tue Dec 26, 2017 2:55 am
by dstastny
I have been working with trying to utilize the newlib function __translate_amiga_to_unix_path_name but it seems to introduce and issue I cant wrap my head around.

Below are 3 simple programs. The first "one.c" uses the function to translate a sample path works fine.

Code: Select all

/*
    gcc -o one one.c

    This works

*/

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <amiga_platform.h>
#include <exec/types.h>
#include <proto/dos.h>
#include <proto/exec.h>



int main() {
    struct NameTranslationInfo nti;
    const char* path = "sdk:newlib";
    printf("Path= %s\n",path);
    __translate_amiga_to_unix_path_name(&path,&nti);
    printf("Path= %s\n",path);

/*
    char*  buf = (char*)malloc(PATH_MAX);
    BPTR lck = IDOS->GetProgramDir();
    if (lck != ZERO) {
        if (IDOS->NameFromLock(lck, buf, PATH_MAX)){
            printf("dir=%s\n",buf);
        }
    }
    free(buf);
*/
    return 0;
}

The second "two.c" uses IDOS functions to get the program directory works fine.

Code: Select all

/*
    gcc -o two two.c

    This works

*/

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <amiga_platform.h>
#include <exec/types.h>
#include <proto/dos.h>
#include <proto/exec.h>



int main() {
/*
    struct NameTranslationInfo nti;
    const char* path = "sdk:newlib";
    printf("Path= %s\n",path);
    __translate_amiga_to_unix_path_name(&path,&nti);
    printf("Path= %s\n",path);
*/

    char*  buf = (char*)malloc(PATH_MAX);
    BPTR lck = IDOS->GetProgramDir();
    if (lck != ZERO) {
        if (IDOS->NameFromLock(lck, buf, PATH_MAX)){
            printf("dir=%s\n",buf);
        }
    }
    free(buf);

    return 0;
}

The third "three.c" attempts top combine both these operations into one simple executable but it crashes @IDOS->GetProgramDir and I can for life of me determine why.

Code: Select all

/*
    gcc -o three three.c

    This crashes on call to IDOS->GetProgramDir()

*/

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <amiga_platform.h>
#include <exec/types.h>
#include <proto/dos.h>
#include <proto/exec.h>



int main() {

    struct NameTranslationInfo nti;
    const char* path = "sdk:newlib";
    printf("Path= %s\n",path);
    __translate_amiga_to_unix_path_name(&path,&nti);
    printf("Path= %s\n",path);


    char*  buf = (char*)malloc(PATH_MAX);
    BPTR lck = IDOS->GetProgramDir();
    if (lck != ZERO) {
        if (IDOS->NameFromLock(lck, buf, PATH_MAX)){
            printf("dir=%s\n",buf);
        }
    }
    free(buf);

    return 0;
}


Any assistance would be appreciated as I am trying to builds some tools that interface with the gcc 5.4 but binutils in that build no longer works correctly with non unix semantics. That issue is outside scope of this help request but as interest to what I a messing with this function as I dont want to spin my own :)

This has been baffling me for week to understand whats up but it only happens if I actually reference the function call __translate_amiga_to_unix_path_name


Regards
Doug

Re: Help with __translate_amiga_to_unix_path_name

Posted: Tue Dec 26, 2017 8:36 am
by salass00
If you look more closely at the GR report you can see that the IDOS pointer is NULL when it is trying to get the NameFromLock() function.

This is because of a bug in newlib.library that was fixed in version 53.31.

Basically if the requested minimum version of newlib.library is >= 52.39 it assumes that the resident startup code is being used, rather than checking for the STARTF_RESIDENT flag. This results in the DOSBase and IDOS globals not being set correctly.

Because you are using the __translate_amiga_to_unix_path_name_r() function the minimum newlib.library is 53.21, which is >= 52.39, and that is the cause of your problem.

There is a workaround for this in crtbegin.o in the latest newlib, but until there is an updated SDK you can add this to your program as a quick fix:

Code: Select all

/* Workaround for bug in newlib.library < 53.31 */
const unsigned int __newlib_minversion __attribute__((weak,section(".gnu.linkonce.r.__NewlibVersion"))) = (52 << 16) | 20;
You might also then want to add a version check of your own in the program like:

Code: Select all

int main(void) {
    if (!LIB_IS_AT_LEAST(INewlib->Data.LibBase, 53, 21)) {
        fprintf(stderr, "This program needs newlib.library version 53.21 or newer.\n");
        return RETURN_ERROR;
    }
    /* ... */
}

Re: Help with __translate_amiga_to_unix_path_name

Posted: Tue Dec 26, 2017 9:28 pm
by dstastny
@salass00

Thank you so much! I noticed the NULL IDOS pointer I just could not understand why linking that the function was causing issue. Thank you for acknowledging it was a bug and providing work around.

To be complete for thread here is working example "four.c"

Code: Select all

/*
    gcc -o four four.c

    This works correctly 

*/

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

#include <amiga_platform.h>
#include <exec/exec.h>
#include <proto/dos.h>
#include <proto/exec.h>

/* Workaround for bug in newlib.library < 53.31 */
const unsigned int __newlib_minversion __attribute__((weak,section(".gnu.linkonce.r.__NewlibVersion"))) = (52 << 16) | 20;


extern struct Interface *INewlib;

int main() {
    if (!LIB_IS_AT_LEAST(INewlib->Data.LibBase, 53, 21)) {
        fprintf(stderr, "This program needs newlib.library version 53.21 or newer.\n");
        return RETURN_ERROR;
    }



    struct NameTranslationInfo nti;
    const char* path = "sdk:newlib";
    printf("Path= %s\n",path);
    __translate_amiga_to_unix_path_name(&path,&nti);
    printf("Path= %s\n",path);


    char*  buf = (char*)malloc(PATH_MAX);
    BPTR lck = IDOS->GetProgramDir();
    if (lck != ZERO) {
        if (IDOS->NameFromLock(lck, buf, PATH_MAX)){
            printf("dir=%s\n",buf);
        }
    }
    free(buf);

    return 0;
}

Only final question is my extern declaration correct way to get to the global instance as INewLib was not declared anywhere I can see? I suspect intent is to keep it private although in research it appears if you want to utilize newlib in library your must manually open.


Thanks again for the speedy response!

Regards
Doug

Re: Help with __translate_amiga_to_unix_path_name

Posted: Tue Dec 26, 2017 10:46 pm
by salass00
dstastny wrote: Only final question is my extern declaration correct way to get to the global instance as INewLib was not declared anywhere I can see?
Yes, it is correct.

The newlib interface is private as you guessed so you won't find it in any header file, but all interfaces start with the fields defined by struct Interface.