EmbDev.net

Forum: ARM programming with GCC/GNU tools problem linking assembly to c program


von Vahid A. (Company: ISC) (vahid_6485)


Rate this post
useful
not useful
Hi all
I want to write a program containing a main.c and pmu.h and definition 
of header file in assembly called pmu.s, i wrote these file in this way:
main.c
#include <stdio.h>
#include "pmu.h"

int main(void)
{
  enable_pmu();              // Enable the PMU
  printf("hello world\n");
  return 0;
}

pmu.h
#ifndef _PMU_h
#define _PMU_h
void enable_pmu(void);
#endif


pmu.s
 PRESERVE8
  AREA  v6_pmu, CODE,READONLY
  ARM
  EXPORT enable_pmu
enable_pmu  PROC
  MRC     p15, 0, r0, c15, c12, 0
  ORR     r0, r0, #0x01
  MCR     p15, 0, r0, c15, c12, 0
  BX      lr
  ENDP
 END

when i build this program with eclipse and codesourcery i got this 
error:
Description  Resource  Path  Location  Type
undefined reference to `enable_pmu'  main.c  /test2  line 7  C/C++ 
Problem

this problem looks simple but i searched a lot about that and i cann't 
find the problem could you please help me?
thanks

von Krapao (Guest)


Rate this post
useful
not useful
Your pmu.s is in ARM assembler format but not in GNU assembler for ARM 
format. You should rewrite it

I have no GNU ARM toolchain installed, but for AVR it would look like:

pmu.S
1
#if 0
2
 PRESERVE8
3
  AREA  v6_pmu, CODE,READONLY
4
  ARM
5
  EXPORT enable_pmu
6
enable_pmu  PROC
7
  MRC     p15, 0, r0, c15, c12, 0
8
  ORR     r0, r0, #0x01
9
  MCR     p15, 0, r0, c15, c12, 0
10
  BX      lr
11
  ENDP
12
 END
13
#else
14
.global  enable_pmu
15
  .type  enable_pmu, @function
16
enable_pmu:
17
  ret
18
#endif

File extension is .S (uppercase) in order to indicate that tis is a 
assembler source file and not an intermediate assembler file from the 
toolchain (.s in lowercase).

von Krapao (Guest)


Rate this post
useful
not useful
Sorry the last answer is related to "Forum: ARM programming with GCC/GNU 
tools". For Codesourcery i don't know the assembler syntax.

von Vahid A. (Company: ISC) (vahid_6485)


Rate this post
useful
not useful
thanks dear Krapao for your reply, this assemble code was part of a 
sample code i found in 
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4237.html
for using performance monitoring unit of arm 11. i will search for how 
to rewrite it.

von Vahid A. (Company: ISC) (vahid_6485)


Rate this post
useful
not useful
Can anyone help me to rewrite this assemble code to GNU assemble?
pmu.s
 PRESERVE8
  AREA  v6_pmu, CODE,READONLY
  ARM
  EXPORT enable_pmu
enable_pmu  PROC
  MRC     p15, 0, r0, c15, c12, 0
  ORR     r0, r0, #0x01
  MCR     p15, 0, r0, c15, c12, 0
  BX      lr
  ENDP
 END

i have changed it in this way:

.global enable_pmu
enable_pmu:
MRC     p15, 0, r0, c15, c12, 0
ORR     r0, r0, #0x01
MCR     p15, 0, r0, c15, c12, 0
BX      lr

and it builds with no error but when i run it on my board(OK6410 with 
Linux OS) it says "Illegal Instruction"
 does anybody have any idea what the problem is?
thanks

von Krapao (Guest)


Rate this post
useful
not useful
Now i understand what you try to do.

You try to worl with your toolchain, what is called with KEIL ARM 
toolchain "Compiler support for accessing registers using named register 
variables"
http://www.keil.com/support/man/docs/armcc/armcc_CHDHCIEE.htm

In detail you try something like example 6, but for understanding i 
include example 5 too:

[citation]
You can also use named register variables to access registers within a 
coprocessor. The string syntax within the declaration corresponds to how 
you intend to use the variable. For example, to declare a variable that 
you intend to use with the MCR instruction, look up the instruction 
syntax for this instruction and use this syntax when you declare your 
variable. See Example 5.

Example 5. Setting bits in a coprocessor register using a named register 
variable

register unsigned int PMCR __asm(”cp15:0:c9:c12:0”);

__inline void __reset_cycle_counter(void)
{
    PMCR = 4;
}

Disassembly:

__reset_cycle_counter PROC
    MOV    r0,#4
    MCR    p15,#0x0,r0,c9,c12,#0      ; move from r0 to c9
    BX     lr
    ENDP

In Example 5, PMCR is declared as a register variable of type unsigned 
int, that is associated with the cp15 coprocessor, with CRn = c9, CRm = 
c12, opcode1 = 0, and opcode2 = 0 in an MCR or MRC instruction. The MCR 
encoding in the disassembly corresponds with the register variable 
declaration.

The physical coprocessor register is specified with a combination of the 
two register numbers, CRn and CRm, and two opcode numbers. This maps to 
a single physical register.

The same principle applies if you want to manipulate individual bits in 
a register, but you write normal variable arithmetic in C, and the 
compiler does a read-modify-write of the coprocessor register. See 
Example 6.

Example 6. Manipulating bits in a coprocessor register using a named 
register variable

register unsigned int SCTLR __asm(”cp15:0:c1:c0:0”);

/* Set bit 11 of the system control register */
void enable_branch_prediction(void)
{
    SCTLR |= (1 << 11);
}

Disassembly:

__enable_branch_prediction PROC
    MRC    p15,#0x0,r0,c1,c0,#0
    ORR    r0,r0,#0x800
    MCR    p15,#0x0,r0,c1,c0,#0
    BX     lr
    ENDP
[/citation]

Unfortuantely i can not check your link in detail.

[citation]
Basic example code used to be available as a download from the ARM 
website.  An improved version is now shipped as part of DS-5 (from 
version 5.8 onwards).  Within the DS-5 Bare-metal example package, the 
code is included as part of the "optimization3" example.
[/citation]

I don't find "Basic example code" and DS-5 website is currenty down.

Questions:

1/ Is enable_pmu allowed on OK6410 with Linux OS? The code from your 
first post would work on your board when translated with KEIL?

2/ Is r0 a register you can use in GNU toolchain freely? The code before 
and after the call to enable_pmu doesn't depend on r0?

4/ Did you check whether GNU toolchain allows "named registers" too, so 
you can write enable_pmu in C only instead in 
KEIL-Disassembly-transferred-in-GNU-Assembly-linked-with-GNU-C?

von Krapao (Guest)


Rate this post
useful
not useful

von mthomas (Guest)


Rate this post
useful
not useful
>...
>AREA  v6_pmu, CODE,READONLY
>...

See AREA in the Realview Assembler documentation in ARM's infocenter and 
the about the SECTION-instruction in the GNU Manuals (GNU-Assembler, 
GNU-Linker part of the binutils). You may also have to check the 
scatter-load file in the example from ARM and modify your linker-script 
to reflect the functionality. It seems the instructions for the 
procedure are expected at a special memory-location. It's difficult to 
help without a minimal but complete example.

von Vahid A. (Company: ISC) (vahid_6485)


Attached files:

Rate this post
useful
not useful
Hi Krapao, I attached  Performance Monitor Unit example code for ARM11 
and Cortex-A/R , that I found on 
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4237.html

1/ Is enable_pmu allowed on OK6410 with Linux OS? The code from your 
first post would work on your board when translated with KEIL?

I will appreciate if I could run these samples on OK6410 with Linux OS 
and it’s my goal now. But I don’t know whether its possible or not. I 
didn’t test translating with KEIL, if I’m right KEIL is used for 
bare-metal devices and does not support GNU assemblers!?!?

4/ Did you check whether GNU toolchain allows "named registers" too, so
you can write enable_pmu in C only instead in
KEIL-Disassembly-transferred-in-GNU-Assembly-linked-with-GNU-C?

Based on your advice I wrote a test program for named register 
variables, my test program was:

#include <stdio.h>
int main(void)
{
  register unsigned int APSR __asm("apsr");
  APSR = ~(~APSR | 0x40);
  register unsigned int SCTLR __asm("cp15:0:c1:c0:0");
  void enable_branch_prediction(void)
  {
      SCTLR |= (1 << 11);
  }
  register unsigned int PMCR __asm("cp15:0:c9:c12:0");
  __inline void __reset_cycle_counter(void)
  {
  PMCR = 4;
  }
  register unsigned int cp15_control __asm("cp15:0:c1:c0:0");
  cp15_control |= 0x1;
  printf("Before call function\n");
  enable_branch_prediction();
  __reset_cycle_counter();
  printf("after call function\n");
  return 0;
}

I used Eclipse IDE for C/C++ Developers(Indigo Service Release 1) and 
Sorcery Codebench lite(arm-2011.09-70-arm-none-linux-gnueabi)
But there are some build errors:

invalid register name for 'apsr'
invalid register name for 'APSR'
invalid register name for 'cp15_control'
invalid register name for 'PMCR'
invalid register name for 'SCTLR'
make: *** [main.o] Error 1


do you think these errors says that GNU toolchain doesn’t  allows "named 
registers"?

von Vahid A. (Company: ISC) (vahid_6485)


Rate this post
useful
not useful
dear mthomas thanks for reply, unfortunately I can’t  get your  main 
idea, could you please clarify your purpose with the steps that I should 
done.

When you want to write a program for a device that has OS (same as my 
board that has linux), is it possible for you to manage the memory 
location that your program runs or operating system got the management?

In my case I only want to config performance monitoring registers of 
ARM1176jzf-s processor with c and assembly programs that runs on linux 
OS.
thanks

von Krapao (Guest)


Rate this post
useful
not useful
In your case (OK6410 AND GNU toolchain AND coprocessor use) you are 
about to enter a unknown continent. You are amoung the first maybe this 
very first explorer of this new land.

Your tools are the description of the GNU tools and your processor 
manual and the way others took with KEIL toolchain.

> In my case I only want to config performance monitoring registers of
> ARM1176jzf-s processor with c and assembly programs that runs on linux
> OS.
> if I’m right KEIL is used for bare-metal devices

Then... In Linux access to some registers is possible only in privileged 
modes. "Bare-metal" access like in the KEIL examples is not possible. So 
you have to throw away "maps" from KEIL explorers and you have to find 
another way...

Under Linux there can be a special v6 PMU driver together with a 
Performance Events library (perfevents). Does your Linux on OK6410 has 
this library enabled? If yes then look i the source and examples for 
this library.

I'll stop here, because this is way to far away for me from initial 
question. I'm guessing only and can't give much input now.

von Vahid A. (Company: ISC) (vahid_6485)


Rate this post
useful
not useful
dear Krapao thanks for your advices and hints, it was so useful for me! 
;-)

Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
No account? Register here.