Nakame
Posts: 16
Joined: Fri Jul 05, 2019 9:24 am

Problem with handling multiple functions

Fri Jul 05, 2019 10:24 am

Hello everyone !

First of all i am new to the raspberry PI and bare metal programming in general so i apologize in advance if this question seem easy to you.
i have started my learning of bare metal with a simple function that make a led blink (on gpio16 for starter) using C programming and a cross compiler (wich i am pretty new to using too , by the way) so here is the code :

Code: Select all

int main(void)
{
    int                     i;
    unsigned int            gpio = 16;
    volatile unsigned int   *base;

    base = (unsigned int*)GPIOBASE; // GPIOBASE = 0x3F200000
    base[gpio / 10] |= (OUTPUT << (gpio % 10) * 3); //OUTPUT = 1


     while(1)
    {
        i = 0;
        while (i < 500000)
        {
            i++;
            base[7] |= (1 << gpio); //set gpio to high
        }
        i = 0;
        while (i < 500000)
        {
            i++;
            base[10] |= (1 << gpio); //set gpio 16 to low
        }
    }
}
i am compiling it using the following line : arm-none-eabi-gcc -I./includes/ -O2 -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s -nostartfiles srcs/gpioBlink.c -o kernel.elf
Followed by : arm-none-eabi-objcopy kernel.elf -O binary kernel.img
And everything work just fine. However, when i use the following code :

Code: Select all

int gpioblink(void)
{
    int                     i;
    unsigned int            gpio = 16;
    volatile unsigned int   *base;

    base = (unsigned int*)GPIOBASE; // GPIOBASE = 0x3F200000
    base[gpio / 10] |= (OUTPUT << (gpio % 10) * 3); //OUTPUT = 1


     while(1)
    {
        i = 0;
        while (i < 500000)
        {
            i++;
            base[7] |= (1 << gpio); //set gpio to high
        }
        i = 0;
        while (i < 500000)
        {
            i++;
            base[10] |= (1 << gpio); //set gpio 16 to low
        }
    }
}

int main()
{
    gpioblink();
}
it doesn't work anymore , and i don't understand why. Also you might have noticed that i put the instruction to set the gpio to high INSIDE the INSIDE the while loop that is supposed to be a delay instead of outside, that is because for unknown reason, if i do it that way :

Code: Select all

     while(1)
    {
        i = 0;
        while (i < 500000)
        {
            i++;
        }
        base[7] |= (1 << gpio); //set gpio to high
        i = 0;
        while (i < 500000)
        {
            i++;
        }
        base[10] |= (1 << gpio); //set gpio 16 to low
    }
it doesnt work anymore. I require your help to understand why before i loose the little bit of sanity i managed to keep. Is it possible that my compiler is at fault ? (i tried to install the aarch64-elf-gcc compiler but failed miserably for more than 2 days).

Thank you so much in advance !

bzt
Posts: 374
Joined: Sat Oct 14, 2017 9:57 pm

Re: Problem with handling multiple functions

Fri Jul 05, 2019 12:53 pm

Hi and welcome,

First, there's a "for" construct in C which would make your code much simpler and more readable:

Code: Select all

for(i = 0; i < 500000; i++) {
About your problem, I'm just guessing here (you should compare the disassembly of the two functions to be sure), but I suspect some of your code is optimized away. You could try to use the "static inline" keywords on gpioblink() and see if the disassembly different to the main() only version. You should always use the "volatile" keyword when accessing MMIO registers, for example:

Code: Select all

base = (volatile unsigned int*)GPIOBASE;
While at it, I don't see the point in using the "base" variable. Why don't you simply define base as

Code: Select all

#define GPIOBASE ((volatile unsigned int *)0x3F200000)

GPIOBASE[gpio / 10] = ...
Hope this helps.

Cheers,
bzt

P.s.: almost forgot, to disassemble, use "arm-none-eabi-objdump kernel.elf". Don't get frightened of the assembly instructions, just run a "diff" to see if there's any difference at all. If there is, post the diff here please, so that we can help.

User avatar
DavidS
Posts: 4334
Joined: Thu Dec 15, 2011 6:39 am
Location: USA
Contact: Website

Re: Problem with handling multiple functions

Fri Jul 05, 2019 1:14 pm

Where is the linker script?

Where is your assembly stub (needed to init the stack and memory)?

I would imagine that the failure comes from your stub not setting up the stack correctly (assuming the function call is being made), as C uses the stack in making function calls.
RPi = The best ARM based RISC OS computer around
More than 95% of posts made from RISC OS on RPi 1B/1B+ computers. Most of the rest from RISC OS on RPi 2B/3B/3B+ computers

Nakame
Posts: 16
Joined: Fri Jul 05, 2019 9:24 am

Re: Problem with handling multiple functions

Fri Jul 05, 2019 1:41 pm

Hello again,

First of all thanks for taking the time to help me with that problem.

@Davids
There is no linker script or assembly stub, i assume the compiler does it for me ? the code i linked (+ a .h file with a bunch of defines ) is quite literally the entirety of my program.

EDIT : unless you talk about the start.elf or bootcode.bin ? both file i took from the raspberry pi website and haven't touched since.

@bzt
This help a lot, After adding the "static inline" on gpioBlink(), the program started acting like expected and the led blinked. the diff on both assembly code from the kernel.elf file returned no difference. without the "static inline" however, there is a whole bunch of differences detected (which ill post at the end if you need those).
I did not know of the inline statement, i did a bit a research about it and it look like it tell the compiler how to optimize your code ( i really don't know much about that yet, but i guess if i want to be efficient ill have to learn fast) tho i assume putting that in front of all my functions outside of main is not a solution.

here is the updated code after following your avices :

Code: Select all

static inline int gpioBlink(void)
{
    int                     i;
    unsigned int            gpio = 16;

    GPIOBASE[gpio / 10] |= (OUTPUT << (gpio % 10) * 3); //OUTPUT = 1

    while(1)
    {
        for (i = 0; i < 500000; i++)
            GPIOBASE[7] |= (1 << gpio); //set gpio to high
        for (i = 0; i < 500000; i++)
            GPIOBASE[10] |= (1 << gpio); //set gpio 16 to low
    }
}

int main()
{
    gpioBlink();
}
also do you have any idea on why putting the line "GPIOBASE[7] |= (1 << gpio); " or "GPIOBASE[10] |= (1 << gpio);" (used for setting the gpio on high or low ) doesnt work if i place it OUTSIDE the loop ( loop that is just for delay) ?

Thanks again for your help so far, here is the diff between the single main and 2 functions WITHOUT the static inline, just in case you need it:

Code: Select all

8,27c8,31
<     8000:     e59f2040        ldr     r2, [pc, #64]   ; 8048 <main+0x48>
<     8004:     e1a03002        mov     r3, r2
<     8008:     e5921004        ldr     r1, [r2, #4]
<     800c:     e3811701        orr     r1, r1, #262144 ; 0x40000
<     8010:     e5821004        str     r1, [r2, #4]
<     8014:     e59f1030        ldr     r1, [pc, #48]   ; 804c <main+0x4c>
<     8018:     e593201c        ldr     r2, [r3, #28]
<     801c:     e2511001        subs    r1, r1, #1
<     8020:     e3822801        orr     r2, r2, #65536  ; 0x10000
<     8024:     e583201c        str     r2, [r3, #28]
<     8028:     1afffffa        bne     8018 <main+0x18>
<     802c:     e59f1018        ldr     r1, [pc, #24]   ; 804c <main+0x4c>
<     8030:     e5932028        ldr     r2, [r3, #40]   ; 0x28
<     8034:     e2511001        subs    r1, r1, #1
<     8038:     e3822801        orr     r2, r2, #65536  ; 0x10000
<     803c:     e5832028        str     r2, [r3, #40]   ; 0x28
<     8040:     1afffffa        bne     8030 <main+0x30>
<     8044:     eafffff2        b       8014 <main+0x14>
<     8048:     3f200000        .word   0x3f200000
<     804c:     0007a120        .word   0x0007a120
---
>     8000:     e92d4010        push    {r4, lr}
>     8004:     ebffffff        bl      8008 <gpioBlink>
> 
> 00008008 <gpioBlink>:
>     8008:     e59f2040        ldr     r2, [pc, #64]   ; 8050 <gpioBlink+0x48>
>     800c:     e1a03002        mov     r3, r2
>     8010:     e5921004        ldr     r1, [r2, #4]
>     8014:     e3811701        orr     r1, r1, #262144 ; 0x40000
>     8018:     e5821004        str     r1, [r2, #4]
>     801c:     e59f1030        ldr     r1, [pc, #48]   ; 8054 <gpioBlink+0x4c>
>     8020:     e593201c        ldr     r2, [r3, #28]
>     8024:     e2511001        subs    r1, r1, #1
>     8028:     e3822801        orr     r2, r2, #65536  ; 0x10000
>     802c:     e583201c        str     r2, [r3, #28]
>     8030:     1afffffa        bne     8020 <gpioBlink+0x18>
>     8034:     e59f1018        ldr     r1, [pc, #24]   ; 8054 <gpioBlink+0x4c>
>     8038:     e5932028        ldr     r2, [r3, #40]   ; 0x28
>     803c:     e2511001        subs    r1, r1, #1
>     8040:     e3822801        orr     r2, r2, #65536  ; 0x10000
>     8044:     e5832028        str     r2, [r3, #40]   ; 0x28
>     8048:     1afffffa        bne     8038 <gpioBlink+0x30>
>     804c:     eafffff2        b       801c <gpioBlink+0x14>
>     8050:     3f200000        .word   0x3f200000
>     8054:     0007a120        .word   0x0007a120

User avatar
DavidS
Posts: 4334
Joined: Thu Dec 15, 2011 6:39 am
Location: USA
Contact: Website

Re: Problem with handling multiple functions

Fri Jul 05, 2019 2:02 pm

Nakame wrote:
Fri Jul 05, 2019 1:41 pm
Hello again,

First of all thanks for taking the time to help me with that problem.

@Davids
There is no linker script or assembly stub, i assume the compiler does it for me ? the code i linked (+ a .h file with a bunch of defines ) is quite literally the entirety of my program.

EDIT : unless you talk about the start.elf or bootcode.bin ? both file i took from the raspberry pi website and haven't touched since.
No the compiler does not take care of that for you. As there is no operating system in use the compiler has no way of knowing where you need the stack to be, so you have to set all that up before you get to the C code. Also the OS is normally responsible for the zero initilaization of the bss segment space, you do not have an OS to do this for you so you have to write a stub that does this before you get to the C code.

This is definitely your problem. You will not be able to call a function until you have at minimum a correctly setup stack on R13.
@bzt
This help a lot, After adding the "static inline" on gpioBlink(), the program started acting like expected and the led blinked. the diff on both assembly code from the kernel.elf file returned no difference. without the "static inline" however, there is a whole bunch of differences detected (which ill post at the end if you need those).
I did not know of the inline statement, i did a bit a research about it and it look like it tell the compiler how to optimize your code ( i really don't know much about that yet, but i guess if i want to be efficient ill have to learn fast) tho i assume putting that in front of all my functions outside of main is not a solution.

here is the updated code after following your avices :

Code: Select all

static inline int gpioBlink(void)
{
    int                     i;
    unsigned int            gpio = 16;

    GPIOBASE[gpio / 10] |= (OUTPUT << (gpio % 10) * 3); //OUTPUT = 1

    while(1)
    {
        for (i = 0; i < 500000; i++)
            GPIOBASE[7] |= (1 << gpio); //set gpio to high
        for (i = 0; i < 500000; i++)
            GPIOBASE[10] |= (1 << gpio); //set gpio 16 to low
    }
}

int main()
{
    gpioBlink();
}
also do you have any idea on why putting the line "GPIOBASE[7] |= (1 << gpio); " or "GPIOBASE[10] |= (1 << gpio);" (used for setting the gpio on high or low ) doesnt work if i place it OUTSIDE the loop ( loop that is just for delay) ?

Thanks again for your help so far, here is the diff between the single main and 2 functions WITHOUT the static inline, just in case you need it:

Code: Select all

8,27c8,31
<     8000:     e59f2040        ldr     r2, [pc, #64]   ; 8048 <main+0x48>
<     8004:     e1a03002        mov     r3, r2
<     8008:     e5921004        ldr     r1, [r2, #4]
<     800c:     e3811701        orr     r1, r1, #262144 ; 0x40000
<     8010:     e5821004        str     r1, [r2, #4]
<     8014:     e59f1030        ldr     r1, [pc, #48]   ; 804c <main+0x4c>
<     8018:     e593201c        ldr     r2, [r3, #28]
<     801c:     e2511001        subs    r1, r1, #1
<     8020:     e3822801        orr     r2, r2, #65536  ; 0x10000
<     8024:     e583201c        str     r2, [r3, #28]
<     8028:     1afffffa        bne     8018 <main+0x18>
<     802c:     e59f1018        ldr     r1, [pc, #24]   ; 804c <main+0x4c>
<     8030:     e5932028        ldr     r2, [r3, #40]   ; 0x28
<     8034:     e2511001        subs    r1, r1, #1
<     8038:     e3822801        orr     r2, r2, #65536  ; 0x10000
<     803c:     e5832028        str     r2, [r3, #40]   ; 0x28
<     8040:     1afffffa        bne     8030 <main+0x30>
<     8044:     eafffff2        b       8014 <main+0x14>
<     8048:     3f200000        .word   0x3f200000
<     804c:     0007a120        .word   0x0007a120
---
>     8000:     e92d4010        push    {r4, lr}
>     8004:     ebffffff        bl      8008 <gpioBlink>
> 
> 00008008 <gpioBlink>:
>     8008:     e59f2040        ldr     r2, [pc, #64]   ; 8050 <gpioBlink+0x48>
>     800c:     e1a03002        mov     r3, r2
>     8010:     e5921004        ldr     r1, [r2, #4]
>     8014:     e3811701        orr     r1, r1, #262144 ; 0x40000
>     8018:     e5821004        str     r1, [r2, #4]
>     801c:     e59f1030        ldr     r1, [pc, #48]   ; 8054 <gpioBlink+0x4c>
>     8020:     e593201c        ldr     r2, [r3, #28]
>     8024:     e2511001        subs    r1, r1, #1
>     8028:     e3822801        orr     r2, r2, #65536  ; 0x10000
>     802c:     e583201c        str     r2, [r3, #28]
>     8030:     1afffffa        bne     8020 <gpioBlink+0x18>
>     8034:     e59f1018        ldr     r1, [pc, #24]   ; 8054 <gpioBlink+0x4c>
>     8038:     e5932028        ldr     r2, [r3, #40]   ; 0x28
>     803c:     e2511001        subs    r1, r1, #1
>     8040:     e3822801        orr     r2, r2, #65536  ; 0x10000
>     8044:     e5832028        str     r2, [r3, #40]   ; 0x28
>     8048:     1afffffa        bne     8038 <gpioBlink+0x30>
>     804c:     eafffff2        b       801c <gpioBlink+0x14>
>     8050:     3f200000        .word   0x3f200000
>     8054:     0007a120        .word   0x0007a120
RPi = The best ARM based RISC OS computer around
More than 95% of posts made from RISC OS on RPi 1B/1B+ computers. Most of the rest from RISC OS on RPi 2B/3B/3B+ computers

Nakame
Posts: 16
Joined: Fri Jul 05, 2019 9:24 am

Re: Problem with handling multiple functions

Fri Jul 05, 2019 2:43 pm

@DavidS
What you say make sens to me, however, i DO have just the code i linked and it does work. For exemple i just tried this :

Code: Select all

int gpioHigh(unsigned int const gpio)
{
    GPIOBASE[7] |= (1 << gpio); 
}

int gpioLow(unsigned int const gpio)
{
    GPIOBASE[10] |= (1 << gpio);
}

static inline int   gpioBlink(unsigned int gpio)
{
    int                     i;
    
    while(1)
    {
        for (i = 0; i < 500000; i++)
            gpioHigh(gpio);
        for (i = 0; i < 500000; i++)
            gpioLow(gpio);
    }
}

int gpioSetMode(unsigned int const gpio, int const mode)
{
    GPIOBASE[gpio / 10] |= (mode << (gpio % 10) * 3);
}

int main()
{
    gpioSetMode(16, OUTPUT);
    gpioBlink(16);
}
and that code work as well ( expet if we remove the "static inline" from gpioBlink() ) i do have a warning during compilation : " warning: cannot find entry symbol _start; defaulting to 0000000000008000 " but i read somewhere that the default starting entry was correct so i just ignored it for now. As i said i am no expert tho so if you beleve that the absence of stub is the cause of the problems i listed then ill try to make one but my knowledge of assembly is limited at best. That being said, i knew i would need to learn it anyway, so might as well start now.

User avatar
DavidS
Posts: 4334
Joined: Thu Dec 15, 2011 6:39 am
Location: USA
Contact: Website

Re: Problem with handling multiple functions

Fri Jul 05, 2019 3:48 pm

When it works you are getting lucky that R13 is pointing to memory that is safe to use for the stack. When it fails there is a high probability that you have clobbered your code with the stack.
RPi = The best ARM based RISC OS computer around
More than 95% of posts made from RISC OS on RPi 1B/1B+ computers. Most of the rest from RISC OS on RPi 2B/3B/3B+ computers

bzt
Posts: 374
Joined: Sat Oct 14, 2017 9:57 pm

Re: Problem with handling multiple functions

Sat Jul 06, 2019 10:40 am

Hi,

Yeah I agree with DavidS, you were extremely lucky. Not only because you lack a proper stack, but also because you haven't zerod out the bss, and you have started running your code at the first function found. The entry point is NOT main() by default, but _start(), which should set up the C environment and call main(). You don't have _start(), therefore the execution started at the very first function (which of course was main() when you had only one function).

A very simple and minimal example can be found in my tutorials: 02_multicorec. This implements _start in Assembly which initializes everything needed to run main() on one core only (feel free to use it as-is).

There's also a minimal linker script you can use. Most of the time your code will be compiled to position independent code, so you can be lucky not specifying the memory address your code is loaded to, until you run an instruction which needs it. That's what linker scripts are for, to tell the linker what segments are there at which locations and how to map your code to segments. When you compile a C source on a hosted environment (under an OS), the linker script is provided by the OS under the hood silently. But in freestanding mode, without any OS support and compiling for bare metal, it is your duty to manually write and specify the linker script for the compiler.

EDIT: now I see that your entry point is defaulted to 8000, suggesting you're writing 32 bit code. For that I'd recommend dwelch67's blinker. His linker script is here and the Assembly start up routine that calls main is here. Please note that this example does not zero out bss section, therefore you can't rely on any global variables in your C code, they will contain garbage on start.

Cheers,
bzt

Nakame
Posts: 16
Joined: Fri Jul 05, 2019 9:24 am

Re: Problem with handling multiple functions

Mon Jul 08, 2019 8:51 am

Hello guys, hope you add a lovely week end.

So i have been trying to understand the assembly language i need to do to make a proper stub but i am really struggling here (man , assembly really is hard to read / understand) i managed to compile using the links provided by bzt but the program ( that was making a led blink without the assembly) now doesn't do anything (that i can see).

The start.s contain :

Code: Select all

.globl _start
_start:
    mov sp,#0x8000
    bl main
hang: b hang

.globl PUT32
PUT32:
    str r1,[r0]
    bx lr

.globl GET32
GET32:
    ldr r0,[r0]
    bx lr

.globl dummy
dummy:
    bx lr
basically the code from dwelch67 , i also took his linker which i did not change (and named linker.ld), so my linker.ld file looked like that :

Code: Select all

MEMORY
{
    ram : ORIGIN = 0x8000, LENGTH = 0x10000
}

SECTIONS
{
    .text : { *(.text*) } > ram
    .bss : { *(.bss*) } > ram
}

at this point my C code looked like that :

Code: Select all

int gpioHigh(unsigned int const gpio)
{
    GPIOBASE[7] |= (1 << gpio);
    return(0);
}

int gpioLow(unsigned int const gpio)
{
    GPIOBASE[10] |= (1 << gpio);
    return(0);
}

static inline int   gpioBlink(unsigned int gpio)
{
    int                     i;
    
    while(1)
    {
        for (i = 0; i < 500000; i++)
            gpioHigh(gpio);
        for (i = 0; i < 500000; i++)
            gpioLow(gpio);
    }
    return(0);
}

int gpioSetMode(unsigned int const gpio, int const mode)
{
    GPIOBASE[gpio / 10] |= (mode << (gpio % 10) * 3);
    return(0);
}

int notmain()
{
    gpioSetMode(16, OUTPUT);
    gpioBlink(16);
    return(0);
}
i compiled the whole thing using the following commands :

arm-none-eabi-gcc -I./includes/ -o srcs/main.o -c srcs/main.c -Wall -Wextra -Werror
arm-none-eabi-as srcs/start.s -o start.o
arm-none-eabi-ld srcs/main.o start.o -T link.ld -o kernel.elf
arm-none-eabi-objcopy kernel.elf -O binary kernel.img

and nothing happens. The program seem to compile correctly but the LED doesn't blink on gpio16. I assume something wrong with how i set up my compiler maybe ? I tried to install the aarch64 for gcc compiler from bzt's tutorial (https://github.com/bztsrc/raspi3-tutori ... sscompiler) all Saturday but installation always had a problem at some point.

im currently learning what i can about assembly and the BCM documentation ill keep in touch !

LdB
Posts: 1169
Joined: Wed Dec 07, 2016 2:29 pm

Re: Problem with handling multiple functions

Mon Jul 08, 2019 10:24 am

Problem

Code: Select all

bl main
Main does no exist anywhere in your code.

You have a notmain which is probably where you wanted to go (that is very David Welch he tends to use that rather than main like most).

Change one or the other so it makes sense.

You GPIO set routine is also fundementally flawed .. look at the previous post by elasticbottle for the code.

User avatar
DavidS
Posts: 4334
Joined: Thu Dec 15, 2011 6:39 am
Location: USA
Contact: Website

Re: Problem with handling multiple functions

Mon Jul 08, 2019 11:36 am

Nakame wrote:
Mon Jul 08, 2019 8:51 am
Hello guys, hope you add a lovely week end.

So i have been trying to understand the assembly language i need to do to make a proper stub but i am really struggling here (man , assembly really is hard to read / understand) i managed to compile using the links provided by bzt but the program ( that was making a led blink without the assembly) now doesn't do anything (that i can see).

The start.s contain :

Code: Select all

.globl _start
_start:
    mov sp,#0x8000
    bl main
hang: b hang

.globl PUT32
PUT32:
    str r1,[r0]
    bx lr

.globl GET32
GET32:
    ldr r0,[r0]
    bx lr

.globl dummy
dummy:
    bx lr
First thing is, change bl main to bl notmain
basically the code from dwelch67 , i also took his linker which i did not change (and named linker.ld), so my linker.ld file looked like that :

Code: Select all

MEMORY
{
    ram : ORIGIN = 0x8000, LENGTH = 0x10000
}

SECTIONS
{
    .text : { *(.text*) } > ram
    .bss : { *(.bss*) } > ram
}
Much better.
at this point my C code looked like that :

Code: Select all

int gpioHigh(unsigned int const gpio)
{
    GPIOBASE[7] |= (1 << gpio);
    return(0);
}

int gpioLow(unsigned int const gpio)
{
    GPIOBASE[10] |= (1 << gpio);
    return(0);
}

static inline int   gpioBlink(unsigned int gpio)
{
    int                     i;
    
    while(1)
    {
        for (i = 0; i < 500000; i++)
            gpioHigh(gpio);
        for (i = 0; i < 500000; i++)
            gpioLow(gpio);
    }
    return(0);
}

int gpioSetMode(unsigned int const gpio, int const mode)
{
    GPIOBASE[gpio / 10] |= (mode << (gpio % 10) * 3);
    return(0);
}

int notmain()
{
    gpioSetMode(16, OUTPUT);
    gpioBlink(16);
    return(0);
}
Does that ever work?
i compiled the whole thing using the following commands :

arm-none-eabi-gcc -I./includes/ -o srcs/main.o -c srcs/main.c -Wall -Wextra -Werror
arm-none-eabi-as srcs/start.s -o start.o
arm-none-eabi-ld srcs/main.o start.o -T link.ld -o kernel.elf
arm-none-eabi-objcopy kernel.elf -O binary kernel.img
Huh?
What gcc are you using for that command line?? If you compile this in ARM Linux on the RPi you can just use the included gcc in the Linux.
and nothing happens. The program seem to compile correctly but the LED doesn't blink on gpio16. I assume something wrong with how i set up my compiler maybe ? I tried to install the aarch64 for gcc compiler from bzt's tutorial (https://github.com/bztsrc/raspi3-tutori ... sscompiler) all Saturday but installation always had a problem at some point.

im currently learning what i can about assembly and the BCM documentation ill keep in touch !
What is happening is that you are just going directly to b hang and looping there forever. There is no main to call.

You are branching to the current R15+0, that is to say you are just branching 4 bytes forward. That puts you in the PUT32 routine, which then returns to the B hang instruction and you are in an infinate loop.

For returning from a call you may want to change that BX R14 you are using to a MOV R15,R14 instead, BX can have other consequences.
RPi = The best ARM based RISC OS computer around
More than 95% of posts made from RISC OS on RPi 1B/1B+ computers. Most of the rest from RISC OS on RPi 2B/3B/3B+ computers

Nakame
Posts: 16
Joined: Fri Jul 05, 2019 9:24 am

Re: Problem with handling multiple functions

Mon Jul 08, 2019 12:50 pm

thanks for the replies ! :)

first of all, to be fair, i forgot to change the bl main line before sending it on the forum. i did several tries with the correct function name but the problem doesn't come from that .
my main.c code work very well when compiled on it's own using the commands :
"arm-none-eabi-gcc -I./includes/ -O2 -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s -nostartfiles -Wall -Wextra -Werror srcs/main.c -o kernel.elf "
followed by "arm-none-eabi-objcopy kernel.elf -O binary kernel.img". The led does blink on gpio16. However, when i compile it with start.s, nothing happens anymore. led does not blink.
I compile it with : -"arm-none-eabi-gcc -I./includes/ -O2 -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s -nostartfiles -o
srcs/main.o -c srcs/main.c -Wall -Wextra -Werror"
-"arm-none-eabi-as start.s -o start.o"
-"arm-none-eabi-ld srcs/main.o start.o -T link.ld -o kernel.elf"
-"arm-none-eabi-objcopy kernel.elf -O binary kernel.img"

This process of compiling is the only part i actually did on my own , which is why i suspect i did something wrong there xD .
Huh?
What gcc are you using for that command line?? If you compile this in ARM Linux on the RPi you can just use the included gcc in the Linux.
Now that you mention it , it might be important to note that i am using a linux computer on a x86_64 architecture to compile my program destined for a raspPI 3b. That compiler is supposed to allow me to do that.

User avatar
DavidS
Posts: 4334
Joined: Thu Dec 15, 2011 6:39 am
Location: USA
Contact: Website

Re: Problem with handling multiple functions

Mon Jul 08, 2019 1:23 pm

May be that I am still on my first cup of coffee this morning, though I do not see where you specify that the output of the C compile is a linkable object (has the extension .0). That is one important part.

Still looking at what you have to see if I notice anything else.


Disregard, was my brain not catching what is there.
RPi = The best ARM based RISC OS computer around
More than 95% of posts made from RISC OS on RPi 1B/1B+ computers. Most of the rest from RISC OS on RPi 2B/3B/3B+ computers

User avatar
DavidS
Posts: 4334
Joined: Thu Dec 15, 2011 6:39 am
Location: USA
Contact: Website

Re: Problem with handling multiple functions

Mon Jul 08, 2019 1:40 pm

Ok, your linker script does not specify _start as the entry point. Remember you are omitting the start files, so you need to tell it the entry point.

While it does not matter for that example, you will eventually want to start clearing the memory used for bss.
RPi = The best ARM based RISC OS computer around
More than 95% of posts made from RISC OS on RPi 1B/1B+ computers. Most of the rest from RISC OS on RPi 2B/3B/3B+ computers

Nakame
Posts: 16
Joined: Fri Jul 05, 2019 9:24 am

Re: Problem with handling multiple functions

Mon Jul 08, 2019 2:26 pm

When download and use the blinker01 at https://github.com/dwelch67/raspberrypi ... /blinker01 without midifying anything (exept i turn the blinker01.elf into a kernel.img) nothing happen either ... i dont know if that can help :/

LdB
Posts: 1169
Joined: Wed Dec 07, 2016 2:29 pm

Re: Problem with handling multiple functions

Mon Jul 08, 2019 2:38 pm

I started reading your posts from top ... you tried compiling for 64bit I take it you are on a Pi3 and you assembler has an address 0x3f200000

This is specifically Pi1, PiZero only ... it tells you on the text read it
https://github.com/dwelch67/raspberrypi ... /blinker01
If you open blinker01.c you will also see the addresses

Code: Select all

#define GPFSEL1 0x20200004

Can you just try a pre-compiled image for me and tell me what it says on screen it will stop all the confusion
This sucker will run on any model Pi except a new Pi4 and it will just blink the onboard GREEN led.
https://github.com/LdB-ECM/Raspberry-Pi ... kernel.img

bzt
Posts: 374
Joined: Sat Oct 14, 2017 9:57 pm

Re: Problem with handling multiple functions

Mon Jul 08, 2019 2:47 pm

Hi,

First, I'd like to say well done! Although you haven't produced a working kernel yet, you've definitely made a big progress here!

I'm not sure what ARM mode kernel.img uses. I'd recommend to
a)
use arm-eabi-none-gcc, dwelch67's startup (the startup function alone is enough, you don't need PUT32/GET32, as it does the same as (volatile unsigned int*) define. Those are relevant only to make your Assembly code more readable, but not for C, which is more readable with the define (imho)). In this case create kernel7.img (tells start.elf to use ARMv7 AArch32 for sure).

b)
use aarch64-elf-gcc with my startup example, and name your file kernel8.img (tells start.elf to use ARMv8 AArch64 for sure).

Don't mix these two, because that's guaranteed to not work.

If you have problems with the cross-compiler, then either try CLang (which is by definition a cross-compiler, so you can use the one shipped with your distro just as-is), or please post the error messages you're having with gcc compilation so that we can help. Many have reported isl linking problems without a separate "bin" folder for example, so unfortunately it is not trivial to do. Alternatively you could try to compile on your RPi, in which case you'll be using a native ARM compiler (no compilation for cross-compiler needed), just use "gcc", "ld" etc. shipped with raspbian, without the prefix.

Furthermore, to avoid confusion, I'd recommend to delete the other *.img files from your card, and have only one. When you have more *.img files, then it is possible that you're accidentally booting a different file than the one you've replaced with the fixed code.

About DavidS's advice on the entry point, currently both CLang and gcc defaults to _start, but that's only a convenience, and could change in future compiler version. Therefore it is indeed a good idea to add this line to your linker script to be sure:

Code: Select all

ENTRY(_start)
Cheers,
bzt

Nakame
Posts: 16
Joined: Fri Jul 05, 2019 9:24 am

Re: Problem with handling multiple functions

Mon Jul 08, 2019 3:10 pm

@ldb

Hey , thanks for helping me , so what the screen show is :
Screen resolution 1920 x 1080 Colour depth: 16 line Pitch : 1920
SmartStart v2.07 compiled for Arm6, AARCH32 with 4 core s/w support
Detected cortex-a53 CPU, part id: 0xB03, Cores made ready for use: 4
CPU frequency set to 1200000000 Hz
Timer clock prescale speed 400000000
Deadloop
im pretty sur you just wanted to know the cpu info but hey, you wanted what's on the screen xD

@bzt

I really wanted to make the aarch64 compiler work but no matter the version something went wrong during installation every time i tried, as for clang, it's missing llvm-objcopy , which i found here https://github.com/llvm-mirror/llvm and i am currently installing it , but its taking a long while and i can barely use my computer in the process so i'm probably gonna install it during the night and make a try tomorrow morning .

Also i have not touched the start.elf since i have downloaded it, how do i tell it to take kernel7.img ? (also i never have more than one .img file on my sd card for the very reason you explained. It is already hard enough to debug bare metal for me to add another possible mistake xD )

Thanks all for taking the time to help me with that, it is really appreciated.

LdB
Posts: 1169
Joined: Wed Dec 07, 2016 2:29 pm

Re: Problem with handling multiple functions

Mon Jul 08, 2019 5:08 pm

Yep so you have an original Pi3B not the newer Pi3B+.

So you can only flash onboard LED's thru mailbox if you want to use GPIO you have to have an actual LED on a GPIO port.

Nakame
Posts: 16
Joined: Fri Jul 05, 2019 9:24 am

Re: Problem with handling multiple functions

Mon Jul 08, 2019 5:13 pm

Yep so you have an original Pi3B not the newer Pi3B+.

So you can only flash onboard LED's thru mailbox if you want to use GPIO you have to have an actual LED on a GPIO port.
yes i must have been unclear somewhere but all that mess is just to blink a led that is wired to gpio16.

Basically i am just trying to blink gpio16 high / low

User avatar
DavidS
Posts: 4334
Joined: Thu Dec 15, 2011 6:39 am
Location: USA
Contact: Website

Re: Problem with handling multiple functions

Mon Jul 08, 2019 5:36 pm

Nakame wrote:
Mon Jul 08, 2019 5:13 pm
Yep so you have an original Pi3B not the newer Pi3B+.

So you can only flash onboard LED's thru mailbox if you want to use GPIO you have to have an actual LED on a GPIO port.
yes i must have been unclear somewhere but all that mess is just to blink a led that is wired to gpio16.

Basically i am just trying to blink gpio16 high / low
You did remember a resistor, correct?
RPi = The best ARM based RISC OS computer around
More than 95% of posts made from RISC OS on RPi 1B/1B+ computers. Most of the rest from RISC OS on RPi 2B/3B/3B+ computers

Nakame
Posts: 16
Joined: Fri Jul 05, 2019 9:24 am

Re: Problem with handling multiple functions

Tue Jul 09, 2019 7:21 am

good morning everyone ! (or whatever time it is in your country :) )

thanks to all of you i finally managed to make it work ! Well i took the easy way out , i managed to make llvm-objcopy work, wich allowed me to shamelessly copy bzt's start.S and linker.ld, adapted my own makefile and kept the main.c as is, and everything work as expected (for now xD )

As an added bonus i can now follow bzt's tutorial to help me with future problems. I still don't understand exactly what went wrong with my previous set up , but to be perfectly honest i did so many things without really knowing what i was doing that it is not all that surprising. hopefully this experience taught me one or 2 things ^^.

Thanks to all of you , and i'll probably see you around !

User avatar
DavidS
Posts: 4334
Joined: Thu Dec 15, 2011 6:39 am
Location: USA
Contact: Website

Re: Problem with handling multiple functions

Tue Jul 09, 2019 12:57 pm

Nakame wrote:
Tue Jul 09, 2019 7:21 am
good morning everyone ! (or whatever time it is in your country :) )

thanks to all of you i finally managed to make it work ! Well i took the easy way out , i managed to make llvm-objcopy work, wich allowed me to shamelessly copy bzt's start.S and linker.ld, adapted my own makefile and kept the main.c as is, and everything work as expected (for now xD )

As an added bonus i can now follow bzt's tutorial to help me with future problems. I still don't understand exactly what went wrong with my previous set up , but to be perfectly honest i did so many things without really knowing what i was doing that it is not all that surprising. hopefully this experience taught me one or 2 things ^^.

Thanks to all of you , and i'll probably see you around !
You are welcome.

Feel free to get things wrong, try whatever you wish, it is a good way to learn. Remember if you mess up with your RPi Bare Metal experiments it is not going to hurt anything, so go for it.

Back in the early 1980's, late 1970's this is how many of us learned to program in the first place, get some basics understood, read documentation, experiment, when we fail we tried again until we figured it out.

For some of us this is still today how we learn even more :) .
RPi = The best ARM based RISC OS computer around
More than 95% of posts made from RISC OS on RPi 1B/1B+ computers. Most of the rest from RISC OS on RPi 2B/3B/3B+ computers

Return to “Bare metal, Assembly language”