Makogan
Posts: 71
Joined: Tue May 16, 2017 9:17 pm

What do I need to implement to be able to use objects?

Sat Jun 10, 2017 4:55 am

So, when doing bare metal, many things are non existent a good example is the important malloc() function which you need to implement yourself since the compiler won't magically know how to allocate memory for you. I assume this is the same for new, what libraries, functions, API's.... do I need to implement before being able to do

Code: Select all

Object *object = new Object();
?

dwelch67
Posts: 843
Joined: Sat May 26, 2012 5:32 pm

Re: What do I need to implement to be able to use objects?

Sun Jun 11, 2017 1:03 am

With baremetal you "own" all the ram for the processor, you can use it at will, no reason to ask a system for more, you arent even taking it it is already taken it is yours just use it. As far as system backends to higher level languages, well you have no system so you have to figure out what needes to be added to fake the system if anything. And add it, or dont use languages that have (operating) system dependencies. Stick with Pascal and/or C (or both <grin>) for example.

dwelch67
Posts: 843
Joined: Sat May 26, 2012 5:32 pm

Re: What do I need to implement to be able to use objects?

Sun Jun 11, 2017 1:03 am

What does the compiler generate when you use "new"? Did you try it and examine the compiler output?

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

Re: What do I need to implement to be able to use objects?

Sun Jun 11, 2017 9:45 am

Malloc is public domain there are any number of versions of it look up dmalloc and jemalloc.
Doug Lea's original versions are here
ftp://g.oswego.edu/pub/misc/malloc.c

The reason it doesn't exist is newlib the library the C compiler the Pi is using is used on many different systems.
https://en.wikipedia.org/wiki/Newlib

Like a number of embedded C systems like dietlibc and μClibc it was designed really for MMU_less embedded systems. What you generally do is use static allocation and manage memory yourself because the overhead to manage malloc is not trivial and memory fragmentation is always a problem.

The newlib system on the Pi issues an S_BRK which has a function prototype you just need to handle that function to do the allocation. It is fairly trivial look at Brian SideBotham or my Code which you have seen but neither of us deal with "free".
https://en.wikipedia.org/wiki/Sbrk

You probably also need to realize the deeper reasons under newlib that it has Reentrant and nonreentrant stubs.
http://www.embedded.com/electronics-blo ... lib-Part-2

ARM itself has a couple of versions of C/C++ and it's own performance library but it is a paid product and I think probably Greenhills and Keil will support the Pi.

If you want to try another version of C library you could try something like bionic
https://en.wikipedia.org/wiki/Bionic_(software)
The dynamic memory allocator is usually jemalloc, though it used to be dlmalloc, and still is on some memory-constrained devices; jemalloc gives much higher performance than dlmalloc, but at the cost of extra memory required for bookkeeping.

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

Re: What do I need to implement to be able to use objects?

Sun Jun 11, 2017 10:08 am

dwelch67 wrote:What does the compiler generate when you use "new"? Did you try it and examine the compiler output?
Pretty sure it will generate an _sbrk with the size being the the R0 register.
Last edited by LdB on Sun Jun 11, 2017 10:44 am, edited 1 time in total.

rst
Posts: 289
Joined: Sat Apr 20, 2013 6:42 pm
Location: Germany

Re: What do I need to implement to be able to use objects?

Sun Jun 11, 2017 10:10 am

Using new and delete is relatively easy. You only have to implement the operators like here.

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

Re: What do I need to implement to be able to use objects?

Sun Jun 11, 2017 10:17 am

rst wrote:Using new and delete is relatively easy. You only have to implement the operators like here.
That won't work rst, malloc doesn't work because newlib has no _sbrk implementation so malloc won't work by default.
From circle you need all the code in
https://github.com/rsta2/circle/blob/ma ... /alloc.cpp
as well as all the memory setup stuff

If he used just that code on newlib it would call malloc which will issue an unhandled SBRK call.

Whichever way you go you need to setup the allocation functions :-)

You are right about that is the easiest implementation and those stubs probably already exist in the c++ newlib compiler they just are not implemented at the lower level. I am pretty sure from memory the C++ compiler accepts "new" it just generates an unimplemented call.

Update: It was rather sketchy in the newlib documentation but I think it is implemented as

Code: Select all

void* operator new(size_t size) noexcept 
{ 
    return malloc(size); 
} 
Last edited by LdB on Sun Jun 11, 2017 10:53 am, edited 7 times in total.

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

Re: What do I need to implement to be able to use objects?

Sun Jun 11, 2017 10:29 am

This is my code for _sbrk on newlib which will allocate but never free. RPi_Heap is just a global uint32_t which I use to track heap end.

Code: Select all

.section .text._sbrk, "ax", %progbits
.balign	4
.globl _sbrk;			
.type _sbrk, %function
.syntax unified
.arm
_sbrk:
        ldr     r2, =RPi_Heap
        ldr     r1, =_end
        ldr     r3, [r2]
        cmp     r3, #0
        moveq   r3, r1
        add     r0, r3, r0
        str     r0, [r2]
        mov     r0, r3
        bx      lr
.balign	4
.ltorg										;@ Tell assembler ltorg data for this code can go here
.size	_sbrk, .-_sbrk
I define the heap at the end of linker directive file

Code: Select all

.Heap :
    {
     . = ALIGN(4);
     _end = .; PROVIDE (end = .); /* Any memory from here is free to use so this is end of code and start of heap */
    } > RAM
If you want to support free you need to track allocated blocks which is all the circle allocator is doing.

rst
Posts: 289
Joined: Sat Apr 20, 2013 6:42 pm
Location: Germany

Re: What do I need to implement to be able to use objects?

Sun Jun 11, 2017 2:04 pm

LdB wrote:
rst wrote:Using new and delete is relatively easy. You only have to implement the operators like here.
That won't work rst, malloc doesn't work because newlib has no _sbrk implementation so malloc won't work by default.
From circle you need all the code in
https://github.com/rsta2/circle/blob/ma ... /alloc.cpp
as well as all the memory setup stuff
I was talking about a pure bare metal setup without newlib. But yes, because this is only the C++ wrapper for new and delete you still need some memory allocator. This can be very simple _for the first tests_. Because the RPi has lots of memory, you can omit the free() functionality.

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

Re: What do I need to implement to be able to use objects?

Sun Jun 11, 2017 2:51 pm

Yep and that is all there in circle and is a valid way to do it .. I agree with that :-).

He would have to be careful mixing with newlib because those functions will be defined and he will get clashes.

I tested it on arm-none-eabi-c++.exe from ARM and it does what I expected and "new" anything emits an _sbrk because of the newlib implementation.

Code: Select all

void test (void) {
  int *object = new int();
}
Produces output

Code: Select all

test():
        mov     r0, #4
        b       operator new(unsigned int)
B:
You can see it has loaded register R0 with 4 for size of int and that redirects to malloc which calls an _sbrk. So it was all entirely predictable.

My stupidly simple _sbrk makes "new" automatically work just the free doesn't because it isn't implemented.
Last edited by LdB on Sun Jun 11, 2017 3:13 pm, edited 1 time in total.

dwelch67
Posts: 843
Joined: Sat May 26, 2012 5:32 pm

Re: What do I need to implement to be able to use objects?

Sun Jun 11, 2017 3:03 pm

newlib has _sbrk as well as all the other operating system connections that need to be made as part of your port, if you dont have an operating system AND you want to use newlib (which is not required) then you have to implement that backend. This is the entire point. You dont need newlib you just need to implement whatever your compiler is producing. malloc, _sbrk, memcpy, etc can be trivial to create or find others. Or dont put yourself in that position in the first place.

C++ can be used it just carries more backend baggage, or to say it another way you have to create more baggage to use it, you could use JAVA or Python as well, but also have a lot of baggage you have to create/use. This gets us back to the discussion of lower baggage languages like C and Pascal. You can then wish to use standard C library calls but many have a system component and you are back to roll your own or newlib or other c library, full circle on this discussion.

If you dont want to use Pascal you can use C and may have more baggage to carry depending on what your expectations are if you want to use C++ you have more baggage depending on what your expectations are, any other the language does this or that for you languages you have to implement that in bare metal. It starts to become a question of are you really wanting bare metal, and maybe you should be looking at an RTOS or other OS. If you want the OS experience and not the baremetal experience, then dont program baremetal...

dwelch67
Posts: 843
Joined: Sat May 26, 2012 5:32 pm

Re: What do I need to implement to be able to use objects?

Sun Jun 11, 2017 3:13 pm

I am getting a flat out cant find new.

Code: Select all

pi.o: In function `main':
pi.cpp:(.text+0x14): undefined reference to `operator new(unsigned int)'
pi.cpp:(.text+0x30): undefined reference to `operator new(unsigned int)'
pi.cpp:(.text+0x54): undefined reference to `operator new(unsigned int)'
pi.o:(.ARM.exidx+0x0): undefined reference to `__aeabi_unwind_cpp_pr1'
and reading more up on it that is what it is supposed to do call the functions new() and delete(). which do the alloc, so you can start by implementing those.

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

Re: What do I need to implement to be able to use objects?

Sun Jun 11, 2017 3:17 pm

Are you using gcc++ or g+ ... gcc won't know what "new" is as it's a C compiler :-)
Last edited by LdB on Sun Jun 11, 2017 3:20 pm, edited 1 time in total.

dwelch67
Posts: 843
Joined: Sat May 26, 2012 5:32 pm

Re: What do I need to implement to be able to use objects?

Sun Jun 11, 2017 3:19 pm

But how is this different than calling malloc() in a normal C program which you dont need to do in baremetal, you can choose to do it if you want to build in that complication, but dont really need to...Sure if you try to pull in some useful library (zlib, jpeg, png, etc) you may have to implement some file and other functions, but you dont need newlib to do that, just implement them. On the other hand if you want an operating system use an operating system dont use baremetal. If you want to "understand" how all of this stuff works, then implement it yourself and see how deep and wide it goes dont go grap libraries (newlib) that add more libraries.

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

Re: What do I need to implement to be able to use objects?

Sun Jun 11, 2017 3:21 pm

The newlib is setup to deal with "new" gcc++ or G+ and redirects to malloc it is the default setup on the compiler. You are treating newlib as if it isn't setup as part of the compiler but it takes some effort to remove it. Half (probably more) of the standard C libraries call or use newlib by default on the Pi and are setup to it. Not saying you can't remove newlib but it's a whole lot more effort than fixing the simple problem. The idea of writing your own standard library files sort of defeats what standard library files are.

It's malloc that isn't setup in C on newlib which is why the problems are linked.

By simply providing _sbrk both malloc and new work.. at least on the arm versions of GCC. I don't imagine its any different on the official Pi version 4.8 or 4.9 or whatever it is. I am pretty sure malloc is implemented in the same way because I have seen people playing around redirecting printf on the official versions and they have to deal with _sbrk because it does a malloc.

Try malloc on your c compiler it should work but emit rubbish.
So look at output for this .. I have to use -O0 optimization or else it will get optimized away as object isn't used.
my abc.c file is

Code: Select all

#include <stdio.h>
#include <stdlib.h>
void test (void) {
  int *object = (int*)malloc(4);
}
I get this from this command
g:\pi\gcc_pi_6_2\bin\arm-none-eabi-gcc -Wall -O0 -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s -nostartfiles -specs=nosys.specs -ffunction-sections -Wl,-gc-sections -Wl,-T,rpi.ld abc.c -o kernel.elf -lc -lm -Wa,-a >list.txt

Code: Select all

  12              		.file	"abc.c"
  13              		.section	.text.test,"ax",%progbits
  14              		.align	2
  15              		.global	test
  16              		.syntax unified
  17              		.arm
  18              		.fpu vfp
  19              		.type	test, %function
  20              	test:
  21              		@ args = 0, pretend = 0, frame = 8
  22              		@ frame_needed = 1, uses_anonymous_args = 0
  23 0000 00482DE9 		push	{fp, lr}
  24 0004 04B08DE2 		add	fp, sp, #4
  25 0008 08D04DE2 		sub	sp, sp, #8
  26 000c 0400A0E3 		mov	r0, #4
  27 0010 FEFFFFEB 		bl	malloc
  28 0014 0030A0E1 		mov	r3, r0
  29 0018 08300BE5 		str	r3, [fp, #-8]
  30 001c 00F020E3 		nop
  31 0020 04D04BE2 		sub	sp, fp, #4
  32              		@ sp needed
  33 0024 0088BDE8 		pop	{fp, pc}
  34              		.size	test, .-test
  35              		.ident	"GCC: (GNU Tools for ARM Embedded Processors 6-2017-q1-update) 6.3.1 20170215 (release) [AR
I use a generic linker file rpi.ld nothing special in it.
Then look at your malloc code it outputs ... that is all the problem is :-)

Don't disagree with what you are saying it's just a whole lot of work for a very simple problem which you can solve by providing one function to the standard c files.

You have told him and if he wants to do it then fine ... for my part I think that is crazy unless you are doing something slick or special :-)

Anyway I know what I would do, he is free to follow your advice if he thinks it is better.

rst
Posts: 289
Joined: Sat Apr 20, 2013 6:42 pm
Location: Germany

Re: What do I need to implement to be able to use objects?

Sun Jun 11, 2017 5:34 pm

dwelch67 wrote:But how is this different than calling malloc() in a normal C program which you dont need to do in baremetal, you can choose to do it if you want to build in that complication, but dont really need to...
The difference between new and malloc() is, that new does not only allocate some memory, but it creates an object from a class declaration and automatically calls its constructor function which ensures that the memory space is initialised as implemented by the constructor. On the opposite side delete not only frees the memory space. Prior to that it calls the destructor function of the class, which ensures that member variables which are allocated inside the class are freed as well.

This is one concept of object-oriented programming realised in C++. I personally like the concept of classes as an abstraction of data with functions belonging to it. If you do it right, it's like using Lego bricks and I think it is much easier to produce bigger software using this concept.

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

Re: What do I need to implement to be able to use objects?

Mon Jun 12, 2017 7:33 am

+10 to that rst

It can only be for the most basic types that new can be little more than a thin wrapper around malloc. It isn't guaranteed as there is nothing to stop a system from having two different heaps. Many implementations do combine the systems so they can run one heap and one allocation scheme for simplicity .... but don't assume it.

I guessed it might be true on the arm version of GCC because it's the easiest implementation. It makes it dead simple to get both systems to work as it has one heap to rule them all :-).

Code I used to check:

Code: Select all

extern "C" int kernel_main(int, int, int);
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>			// C standard for uint8_t, uint16_t, uint32_t etc
#include "rpi-smartstart.h"      // Has _sbrk defined

int kernel_main (int, int, int) {
	RPI_InitGraph(800, 600, 32);
	int *object1 = new int;
	*object1 = 7;
	printf("object1: %8lX value: %i\r\n", (uint32_t)object1, *object1);
	int *object2 = new int;
	*object2 = 10;
	printf("object2: %8lX value: %i\r\n", (uint32_t)object2, *object2);
	while (1) {
	}
	return 0;
}
Compiled with
g:\pi\gcc_pi_6_2\bin\arm-none-eabi-g++ -Wall -O2 -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s -nostartfiles -specs=nosys.specs -ffunction-sections -Wl,-gc-sections -Wl,-T,rpi.ld abc.c smartstart.S -o kernel.elf -lc -lm
Produces expected result and GCC new is functioning correctly :-)
Image
I will try some class and object code tonight but pretty sure it will work seamlessly, no reason why it won't.
As I said trivial to get new to work for the c++ compiler my way :-).

rst
Posts: 289
Joined: Sat Apr 20, 2013 6:42 pm
Location: Germany

Re: What do I need to implement to be able to use objects?

Mon Jun 12, 2017 3:29 pm

LdB wrote:It can only be for the most basic types that new can be little more than a thin wrapper around malloc.
Yes, when you do new for a built-in scalar type like int there is no constructor to be called. This is different for self defined classes. But a constructor is also not required then, you have to define one.

Return to “Bare metal”

Who is online

Users browsing this forum: No registered users and 4 guests