EmbDev.net

Forum: ARM programming with GCC/GNU tools asm, linker and C


von Armand I. (iostrym)


Rate this post
useful
not useful
Hi,

I have read some sources that contains in the same file, asm, C and
linker instruction.
But when I compile a source file containing pre-processor instruction
like #define and linker instruction like entry(_start) with arm-elf-as
I've an error. Is it really possible to mix asm, C and linker
instruction and how?

thanks in advance for your help,

Best regards,

von Stefan (Guest)


Rate this post
useful
not useful
I've never seen such a source file. pre-processor instructions mixed
with assembler code, yes - this are the *.S files, but mixed with linker
instructions... no. Can you give an example?

Stefan

von Armand I. (iostrym)


Rate this post
useful
not useful
Stefan wrote:
> I've never seen such a source file. pre-processor instructions mixed
> with assembler code, yes - this are the *.S files, but mixed with linker
> instructions... no. Can you give an example?
>
> Stefan

Here it is : there are linker instruction in this source file whereas
usually I've seen them in a linker script. thanks for your help.

/*
 *  linux/arch/arm/kernel/head-armv.S
 *
 *  Copyright (C) 1994-1999 Russell King
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 *  32-bit kernel startup code for all architectures
 *
 * added S3C4510 code by Mac Wang
 * added S3C4530 code by Arcturus Networks Inc.
 * added S3C2500 code by Arcturus Networks Inc.
 * added TI TMS320DM270 code by Chee Tim Loh
<cheetim_loh@innomedia.com.sg>.
 *
 */
#include <linux/config.h>
#include <linux/linkage.h>

#include <asm/assembler.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>

#define K(a,b,c)  ((a) << 24 | (b) << 12 | (c))

/*
 * We place the page tables 16K below TEXTADDR.  Therefore, we must make
sure
 * that TEXTADDR is correctly set.  Currently, we expect the least
significant
 * "short" to be 0x8000, but we could probably relax this restriction to
 * TEXTADDR > PAGE_OFFSET + 0x4000
 *
 * Note that swapper_pg_dir is the virtual address of the page tables,
and
 * pgtbl gives us a position-independent reference to these tables.  We
can
 * do this because stext == TEXTADDR
 *
 * swapper_pg_dir, pgtbl and krnladr are all closely related.
 */

/*
 *  Kernel startup entry point.
 *
 * The rules are:
 *  r0      - should be 0
 *  r1      - unique architecture number
 *  MMU     - off
 *  I-cache - on or off
 *  D-cache - off
 *
 * See linux/arch/arm/tools/mach-types for the complete list of numbers
 * for r1.
 */

.section ".text.init",#alloc,#execinstr
    .type  stext, #function
ENTRY(stext)

                mov  r12, r0

/*
 * NOTE!  Any code which is placed here should be done for one of
 * the following reasons:
 *
 *  1. Compatability with old production boot firmware (ie, users
 *     actually have and are booting the kernel with the old firmware)
 *     and therefore will be eventually removed.
 *  2. Cover the case when there is no boot firmware.  This is not
 *     ideal, but in this case, it should ONLY set r0 and r1 to the
 *     appropriate value.
 */


#if defined(CONFIG_ARCH_L7200)
/*
 * FIXME - No bootloader, so manually set 'r1' with our architecture
number.
 */
    mov  r1, #MACH_TYPE_L7200
#elif defined(CONFIG_ARCH_INTEGRATOR)
    mov  r1, #MACH_TYPE_INTEGRATOR
#elif defined(CONFIG_ARCH_P52)
    mov  r1, #MACH_TYPE_P52
#elif defined(CONFIG_ARCH_CX821XX)
    mov  r1, #MACH_TYPE_CX821XX
#elif defined(CONFIG_ARCH_SWARM)
    mov  r1, #MACH_TYPE_SWARM
#elif defined(CONFIG_BOARD_SNDS100)
    mov  r1, #MACH_TYPE_SNDS100
#elif defined (CONFIG_BOARD_SMDK40100)
    mov  r1, #MACH_TYPE_S3C3410
#elif defined (CONFIG_BOARD_MBA44)
    mov  r1, #MACH_TYPE_S3C44B0X
#elif defined(CONFIG_BOARD_SMDK2500)
    mov r1, #MACH_TYPE_SMDK2500
#elif defined(CONFIG_BOARD_S3C2500REFRGP)
    mov  r1, #MACH_TYPE_S3C2500REFRGP
#elif defined(CONFIG_ARCH_LPC)
    mov r1, #MACH_TYPE_LPC22XX & 0xff
    orr r1, r1, #MACH_TYPE_LPC22XX & 0xff00
#endif

    mov  r0, #F_BIT | I_BIT | MODE_SVC  @ make sure svc mode
    msr  cpsr_c, r0      @ and all irqs disabled


#if defined(CONFIG_ARCH_ATMEL)

        adr  r5, LC0
        ldmia  r5, {r5, r6, r8, r9, sp}      @ Setup stack

        /*  Copy data sections to their new home.  */


        /*  Clear BSS */
        mov  r4, #0
1:      cmp  r5, r8
        strcc  r4, [r5],#4
        bcc  1b

/* FIXME */
#if 0
        /*  Put initial values into stack.  This would normally be done
        by sched_init() in kernel/sched.c, but that would overwrite the
        stack we're already using.  That would be bad.
        */
        mov r5, sp
        sub r5, r5, #0x2000
        ldr r4, L_STACK_MAGIC
        str r4, [r5], #4
        ldr r4, L_STACK_UNTOUCHED_MAGIC
1:      cmp r5, sp
        strcc r4, [r5], #4
        bcc 1b
#endif
        /*  Pretend we know what our processor code is (for arm_id)   */

@@@  ldr     r2, =0x41000000
@@@  orr  r2, r2, #0x7000    @ FIXME --> 0x41007000

  ldr  r2, L_AT91_SF_CIDR
  ldr  r2, [r2]    @ read processor id

  str     r2, [r6]
  mov     r2, #MACH_TYPE_ATMEL
  str     r2, [r9]

        mov fp, #0
        b  start_kernel

LC0:  .long  __bss_start
        .long  processor_id
        .long  _end
  .long   __machine_arch_type
        .long  init_task_union+8192
#endif


    adr  lr, __ret      @ return address
    add  pc, r10, #12      @ initialise processor
              @ (return control reg)

__switch_data:  .long  __mmap_switched
    .long  SYMBOL_NAME(compat)
    .long  SYMBOL_NAME(__bss_start)
    .long  SYMBOL_NAME(_end)
    .long  SYMBOL_NAME(processor_id)
    .long  SYMBOL_NAME(__machine_arch_type)
    .long  SYMBOL_NAME(cr_alignment)
    .long  SYMBOL_NAME(init_task_union)+8192

__ret:    ldr  lr, __switch_data

    mov  pc, lr

    /*
     * This code follows on after the page
     * table switch and jump above.
     *
     * r0  = processor control register
     * r1  = machine ID
     * r9  = processor ID
     */
    .align  5

__mmap_switched:
    adr  r3, __switch_data + 4
    ldmia  r3, {r2, r4, r5, r6, r7, r8, sp}@ r2 = compat
              @ sp = stack pointer
    str  r12, [r2]

#ifdef CONFIG_RAM_ATTACHED_ROMFS
# ifdef CONFIG_ARCH_DM270
/*
 *  Move ROM filesystem above bss :-)
 */
    ldr r3, L_DM270_ROMFS      @ Get end of data

    ldr r10, [r3, #8]      @ Get size of ROMFS (big-endian)
#ifndef CONFIG_CPU_BIG_ENDIAN
    mov r2, #0        @ Convert to little-endian
    and fp, r10, #0x000000ff
    orr r2, r2, fp, lsl #24
    and fp, r10, #0x0000ff00
    orr r2, r2, fp, lsl #8
    and fp, r10, #0x00ff0000
    orr r2, r2, fp, lsr #8
    and fp, r10, #0xff000000
    orr r2, r2, fp, lsr #24
    mov r10, r2
#endif
    add r10, r10, #8      @ Allow for rounding
    bic r10, r10, #3      @ Whole words

    ldr fp, L_DM270_ROMFS + 4    @ Set up destination
    mov r2, r3        @ Copy of _edata

    add r3, r3, r10        @ Copy from end
    add fp, fp, r10
    ldr r10, L_DM270_RAMSTART
    str fp, [r10]

_copy_romfs:
    ldr r10, [r3, #-4]!      @ Copy dword
    str r10, [fp, #-4]!
    cmp r3, r2        @ Check if at end
    bne _copy_romfs
# endif
#endif

    mov  fp, #0        @ Clear BSS (and zero fp)
1:    cmp  r4, r5
    strcc  fp, [r4],#4
    bcc  1b

    str  r9, [r6]      @ Save processor ID
    str  r1, [r7]      @ Save machine type
#ifdef CONFIG_ALIGNMENT_TRAP
    orr  r0, r0, #2      @ ...........A.
#endif
    bic  r2, r0, #2      @ Clear 'A' bit
    stmia  r8, {r0, r2}      @ Save control register values
    b  SYMBOL_NAME(start_kernel)


/*
 * Exception handling.  Something went wrong and we can't
 * proceed.  We ought to tell the user, but since we
 * don't have any guarantee that we're even running on
 * the right architecture, we do virtually nothing.
 * r0 = ascii error character:
 *  a = invalid architecture
 *  p = invalid processor
 *  i = invalid calling convention
 *
 * Generally, only serious errors cause this.
 */
__error:
#ifdef CONFIG_DEBUG_LL
    mov  r8, r0        @ preserve r0
    adr  r0, err_str
    bl  printascii
    mov  r0, r8
    bl  printch
#endif
#ifdef CONFIG_ARCH_RPC
/*
 * Turn the screen red on a error - RiscPC only.
 */
    mov  r0, #0x02000000
    mov  r3, #0x11
    orr  r3, r3, r3, lsl #8
    orr  r3, r3, r3, lsl #16
    str  r3, [r0], #4
    str  r3, [r0], #4
    str  r3, [r0], #4
    str  r3, [r0], #4
#endif
1:    mov  r0, r0
    b  1b

#ifdef CONFIG_DEBUG_LL
err_str:  .asciz  "\nError: "
    .align
#endif

/*
 * Read processor ID register (CP#15, CR0), and look up in the
linker-built
 * supported processor list.  Note that we can't use the absolute
addresses
 * for the __proc_info lists since we aren't running with the MMU on
 * (and therefore, we are not in the correct address space).  We have to
 * calculate the offset.
 *
 * Returns:
 *  r5, r6, r7 corrupted
 *  r8  = page table flags
 *  r9  = processor ID
 *  r10 = pointer to processor structure
 */
__lookup_processor_type:
    adr  r5, 2f
    ldmia  r5, {r7, r9, r10}
    sub  r5, r5, r10      @ convert addresses
    add  r7, r7, r5      @ to our address space
    add  r10, r9, r5
#ifdef CONFIG_CPU_WITH_MCR_INSTRUCTION
    mrc  p15, 0, r9, c0, c0    @ get processor id
#else
# warning   "FIXME: Get Processor ID without MCR Instruction"
    @ A possible code
    @ldr  r9, PROCESSOR_ID_MEM_LOCATION
    @ldr  r9, [r9]
#ifdef CONFIG_ARCH_DM270
    ldr  r9, L_DM270_PID
#endif
#endif
1:    ldmia  r10, {r5, r6, r8}    @ value, mask, mmuflags
    and  r6, r6, r9      @ mask wanted bits
    teq  r5, r6
    moveq  pc, lr
    add  r10, r10, #36      @ sizeof(proc_info_list)
    cmp  r10, r7
    blt  1b
    mov  r10, #0        @ unknown processor
    mov  pc, lr

/*
 * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for
 * more information about the __proc_info and __arch_info structures.
 */
2:    .long  __proc_info_end
    .long  __proc_info_begin
    .long  2b
    .long  __arch_info_begin
    .long  __arch_info_end

/*
 * Lookup machine architecture in the linker-build list of
architectures.
 * Note that we can't use the absolute addresses for the __arch_info
 * lists since we aren't running with the MMU on (and therefore, we are
 * not in the correct address space).  We have to calculate the offset.
 *
 *  r1 = machine architecture number
 * Returns:
 *  r2, r3, r4 corrupted
 *  r5 = physical start address of RAM
 *  r6 = physical address of IO
 *  r7 = byte offset into page tables for IO
 */
__lookup_architecture_type:
    adr  r4, 2b
    ldmia  r4, {r2, r3, r5, r6, r7}  @ throw away r2, r3
    sub  r5, r4, r5      @ convert addresses
    add  r4, r6, r5      @ to our address space
    add  r7, r7, r5
1:    ldr  r5, [r4]      @ get machine type
    teq  r5, r1
    beq  2f
    add  r4, r4, #SIZEOF_MACHINE_DESC
    cmp  r4, r7
    blt  1b
    mov  r7, #0        @ unknown architecture
    mov  pc, lr
2:    ldmib  r4, {r5, r6, r7}    @ found, get results
    mov  r7, r7, lsr #18      @ pagetable byte offset
    mov  pc, lr

L_AT91_SF_CIDR: .long  0xfff00000

#ifdef CONFIG_ARCH_DM270
L_DM270_PID:  .long  0xd2700000

# ifdef CONFIG_RAM_ATTACHED_ROMFS
.global  _ramstart
_ramstart:  .long  0

L_DM270_ROMFS:  .long  _edata
    .long  _ebss

L_DM270_RAMSTART:
    .long  _ramstart
# endif
#endif

von Martin Thomas (Guest)


Rate this post
useful
not useful
It looks like a "usual" asm with preprocessor-code. Maybe the
instructions which "look like" linker-options are preprocessor-macros
defined in the inlcuded files.

Martin Thomas

von Stefan (Guest)


Rate this post
useful
not useful
Same opinion like Martin.

I think ENTRY is a macro e.g. in linkage.h. Maybe something like this

#define ENTRY(X)               \
                  .global X##; \
X##:

which gives for ENTRY(stext):

.global stext; stext:

(from http://www.ussg.iu.edu/hypermail/linux/kernel/0302.1/0128.html)

von Armand I. (iostrym)


Rate this post
useful
not useful
You are right.

in the fiel linkage.h, there is the following lines :

#define ENTRY(name) \
  .globl SYMBOL_NAME(name); \
  ALIGN; \
  SYMBOL_NAME_LABEL(name)

and

#define SYMBOL_NAME_LABEL(X) X##:

#define ALIGN __ALIGN

and

#if defined(_i386_) && defined(CONFIG_X86_ALIGNMENT_16)
#define __ALIGN .align 16,0x90
#define __ALIGN_STR ".align 16,0x90"
#else
#define __ALIGN .align 4,0x90
#define __ALIGN_STR ".align 4,0x90"
#endif

so all is clear, it's asm with pre-processor code.

The aim of such a pre-processor code seems to use ENTRY(stext) in the
linker script. isn't it ? because if I understand the precedent lines,

  .globl SYMBOL_NAME(name); \
  ALIGN; \
  SYMBOL_NAME_LABEL(name)

doesn't define an entry point, there still need an ENTRY command in the
linker script.

von Stefan (Guest)


Rate this post
useful
not useful
armand iostrym wrote:

> The aim of such a pre-processor code seems to use ENTRY(stext) in the
> linker script. isn't it ?

Not at all. The linker script is not generated from these lines. The
linker script doesn't get output from the pre-processor.

You (or someone else) write the linker script with the definition of the
one and only entry point. Therefor you have to prepare your sources so
that this entry point is available. In order to do this you define a
symbol stext, start, _start or my_ugly_entry_point in your sourcecode.
Some people even use several names to be sure ;-)

> because if I understand the precedent lines,
>
>   .globl SYMBOL_NAME(name); \
>   ALIGN; \
>   SYMBOL_NAME_LABEL(name)
>
> doesn't define an entry point,

Yes. These lines define a label 'name:' for the assembler and make this
label a global symbol '.globl name' so the linker knows this symbol when
other object files want to use this symbol.

>  there still need an ENTRY command in the
> linker script.

You can define several global symbols with ENTRY(name...) in the
assembler source files. But you need only one ENTRY in the linker script
(or use one of the default methods
http://linux.web.cern.ch/linux/slc4/docs/rhel-ld-en-4/simple-commands.html)
- what you put with ENTRY() in the linker script will be the address of
the first instruction of your application.

von Armand I. (iostrym)


Rate this post
useful
not useful
Thanks, it confirms waht I thought. Things are getting clearer now.

It's really nice to all of you to help me like that.

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.