need help with a weird result when program a simple example.

Hi,
I need help with an issue with my program running on BB.
This is a stand alone application which run on U-boot to turn on and off the LED.
Somehow I cannot pass the variable to one of my function.

Let I summary here:
I defined LED0 = 149 with:
#define LED0 149

I have a function which call clear_pin(u32 pin_num) which is called from the main function as clear_pin(LED0). Inside my clear_pin function I print out the value I receive by the command:
printf (“Clear Pin %d\n”, pin_num);
and I got:
Clear Pin 1
after this I have to set a constant for this variable and the board did turn off the LED. I mean all of the function after that work well which can turn on and off the LED. This is really weird because there is nothing wrong with syntax. I just don’t sure if there is sth with compiler or u-boot which I didn’t know about it yet. I cannot understand what happens, so I need help. I attach my program and this is the result when I run my program:

OMAP3 beagleboard.org # go 80300000

Starting application at 0x80300000 …

Clear Pin 1
Set Value: 2097152

Application terminated, rc = 0x0

Another issue is when I try to use the struct which I commented in my program, the program just get hang at:

Starting application at 0x80300000 …

I know that my questions are too simple, but because I am learning. So I am really appreciate when you spent your time to help me.

Best regards,
Thang Nguyen

test_gpio.c (2.29 KB)

Hi,

This is a shot in the dark and may not have anything to do with your
issue, but here goes:

ARM has several different ways to translate C function calls into
assembly language. These are usually called Application Binary
Interfaces (ABIs) or Embedded ABIs (EABIs). Each [E]ABI has different
ways to assign arguments and results to registers, and handles the
stack differently. It's critical that your application program uses
the same [E]ABI as the stdio library (libc) or it won't be able to
pass arguments correctly. It's also necessary for your application
program to use an [E]ABI that's compatible with U-boot.

The gnu compiler gcc sets ABI using the "-mabi" option. I don't know
what's appropriate for U-boot and whatever libc you're using.

In addition, there's usually a "crtso" (C run-time start-off) file
(usually assembly language) that gets linked with your application.
"crtso" sets up the stack. You must use the correct "crtso" for U-
boot and your ABI. Once again, I don't know which is correct for U-
Boot.

All this is normally taken care of automatically by the compiler and
linker, provided that you set the options correctly. You can see
which options are getting used by running gcc with the "-v" (Verbose)
option.

Try calling printf() from the main program with multiple arguments and
see if the values are getting printed properly. printf() seems to be
handling the first argument fine, but you don't know if the rest of
its arguments are being passed correctly. It's very hard to debug if
you can't trust printf().

Hope this helps,
John

John,
But the issue is all of the functions setmem32, setmem16, setbit works well when I call them directly. Even in this example, when I call setbit in clear_pin function it did turn off the LED. Somehow it only not work with the set_pin function.

Thanks,
Thang Nguyen

From what I can tell, the code looks good as far as C is concerned.
One suggestion is to declare all pointers to hardware registers as
"volatile" so the compiler doesn't try to optimize loads and stores,
resulting in strange hardware behavior.

Another suggestion is to tell the compiler to save the assembly
language it generated so you can review it. It's rare to find bugs in
the compiler, but sometimes this can help you find where you made your
mistake. This might help you see what happened when you had "struct
pin_map gpio_temp" declared.

Speaking which, some C compilers have issues with returning structures
as function values, as you did in get_gpio_bank(). You should be able
to do it, but it may require setting the correct compiler options. It
might be instructive to see what assembly language was generated by
this. Something may be wrong with stack initialization, which is an
[E]ABI issue.

John

Is test_gpio() your entry point…? If so the prototype for it is wrong and it should be declared as “int test_gpio (int argc, char *argv[])”. The first thing you should do within a U-Boot application is call “app_startup (argv);”. These two issues might fix up a wonky stack issue which could be causing the problem.

If this doesn’t solve the problem then let me know and I’ll try it on my BB tomorrow.

Mike

I added the lines you told me, and it returned with same result. I attached the new update file here.

Total Size = 0x000081ec = 33260 Bytes

Start Addr = 0x80300000

OMAP3 beagleboard.org # go 80300000

Starting application at 0x80300000 …

Clear Pin 1

Application terminated, rc = 0x0

OMAP3 beagleboard.org #

Somehow these lines didn’t run cause I don’t see the print out of these commands.

I highly appreciate if you can check if for me.
There are something else in my file if the struct didn’t work. Could you please check it for me too. Those I put in the comment with not work are the part I implement the struct variable.

The last issue I want to ask is when I do make distclean, there is an error with a file. I don’t sure if this affect anything but it will not clean the old build files.

naruto@naruto-laptop:~/oe/sources/u-boot-main$ make CROSS_COMPILE=arm-none-linux-gnueabi- distclean
examples/mem_to_mem_idma2intr
examples/sched examples/smc91111_eeprom
examples/test_burst examples/timer
make: examples/mem_to_mem_idma2intr: Command not found
make: *** [clean] Error 127

test_gpio.c (2 KB)

Okay, I’ve worked out what the problem is… just haven’t worked out an elegant solution yet :slight_smile:

The problem is that the compile/link of the examples is broken and the clear_pin() function is becoming the main entry point for the standalone application. If you run “go 80300000 i dont believe it” you should see it clearing pin 5. Because argc is 5 which is mapping (luckily) to your pin_num parameter.

It is supposed to be that the first function in the first object during the link becomes the entry function. However, objdump is showing this is not always the case. Until I work out what the fix for the Makefile is, you can use objdump to get the offset of the test_gpio function by using this command:

{path_to_xcompiler}/bin/objdump -t test_gpio | grep test_gpio$

You can then use this address in the “go” command. So, if objdump outputs that test_gpio() is at 80300010 then use “go 80300010”.

Your other problem is that you can’t pass or return a “struct” in C, you have to pass a pointer to it instead. Have a read of this link (esp. Chapter 5): http://pweb.netcom.com/~tjensen/ptr/pointers.htm

A better fix is to edit u-boot-main/config.mk and:

  1. Search for “freestanding” (latest U-Boot is on line 136)
  2. Insert “-fno-toplevel-reorder” to the CPPFLAGS

Then the expected behaviour (first function in the C file is called) comes back.

Mike

Mike,
Thank for your help.
Is there anything I can read to understand what you told me (about the objdump as well as compile/link)? I only understand generally what is link prossess but I don’t know specificly about each object and how these objects work in this case. For example why “Insert “-fno-toplevel-reorder” to the CPPFLAGS” will make it work?
sorry about my dumb question ^_^.
Thanks,
Thang Nguyen

Mike,

Good detective work figuring out which function 8030.0000 was calling.

My understanding of the C run-time start-off (crtso) file is that it
sets up the stack using information from the linker and calls main().
Usually crtso.o is the first file listed in the linker command so it's
included first in the executable image. I don't know what it would
do in Thang Nguyen's case where there isn't a function named main().
I suspect that there is no crtso.o, otherwise the linker would
complain there is no function main(). This would mean that no stack
is set up, so who knows what the run-time is using for a stack --
maybe just using uboot's own stack?

You CAN pass and return structs in ANSI C. I do it all the time with
small structures like [x, y] coordinates. You couldn't do it in K&R
C. This is mentioned in Chapter 5 of http://pweb.netcom.com/~tjensen/ptr/pointers.htm.

John

The general process is that gcc runs its preprocessor and processes things like #defines, then it converts the C program source into assembler. The assembler code is normally hidden from the end user, but you can ask gcc to produce it by giving it a “-S” option.

These assembler sources are then converted into CPU machine code and saved into object files (one object file for each C source file). Finally once all the object files have been produced they are “linked” together, including any platform requirements and libraries. The linker also takes care of any external dependencies where code is loaded at runtime from external files.

Things are a bit different when you aren’t running inside an operating system and so various flags are needed to tell gcc to produce a program that doesn’t rely on system libraries and doesn’t use the platforms default _start code… This is done with the “-ffreestanding” flag. One of our “freestanding” requirements is that we load the program to a specific address in memory and then the CPU to start running code at that same memory address… so the first machine code instruction needs to appear at the very beginning of the file…

This particular problem is really the fault of the “-Os” (optimise for small size) flag. This turns on various gcc optimisations, including reordering of code and data objects. The “-fno-toplevel-reorder” option keeps most of those “-Os” optimisations, but turns off the re-ordering of top level functions.

You could try reading here for an introduction to gcc:
http://www.network-theory.co.uk/docs/gccintro/

“objdump” just dumps ELF file information, so this is an okay introduction to the ELF file format:
http://www.linuxjournal.com/article/1059

If you want more general info then “man gcc” is a, er, very dry read… or there’s always Google… :]

Correct, there’s no crtso routine. U-Boot supplies an app_startup() function which is similar - it zeros the stack and sets up a jump table so that you can callback to functions provided by U-Boot. printf() is actually handled by U-Boot as the output could be going pretty much anywhere.

Hi,
I read the GCC Introduction site you gave me. It’s really helpful.
I wonder is there anyway to use the debug method for the cross platform compiler or not? Especially in my case. If there is any method, please let me know.

Thank you so much for all of your information.

Best regards,

Thang Nguyen

Actually I still don’t understand how compiler know which one is the first function? cause in this case there is no main() function. I mean what indicates the first function?

I followed your instruction inserting the flag to the config.mk file (after ffreestanding). After rebuild and run the objdump, I still get the address of test_gpio function is 80300010.

Technically the answer is yes, but practically the answer is no. You could enable debugger support quite easily in the compile and single step the application / add breakpoints etc… the problem is that since this is a freestanding application, there is no operating system and no debugger to handle the application’s interrupts when it hits a breakpoint…

The most practical thing to do would be to write modules under a full linux environment where they can be debugged and then, once they are stable, incorporate those into the U-Boot standalone application.

The “first function” is the first function that GCC encounters as its processing the source code file… :slight_smile:

Could you post your source code and the output of the make…? Its possible that something is sneaking in before your function… you can also use objdump to show what has been located at the 80300000 entry address and that might help work out whats going on…

Thanks,

Mike