gas_marco_advance

在查阅unicore的memcpy函数时,感觉学到了不少东西,今天把一周的东西整理下,留下了这个文档,方便以后查阅

文件 asm/hwcap.h
/*
* linux/arch/unicore/include/asm/hwcap.h
*
* Code specific to PKUnity SoC and UniCore ISA
* Fragments that appear the same as the files in arm or x86
*
* Copyright (C) 2001-2008 GUAN Xue-tao
*
* 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.
*/
#ifndef __UNICORE_HWCAP_H__
#define __UNICORE_HWCAP_H__
/*
* HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
*/
#define HWCAP_MSP   1
#define HWCAP_UNICORE16   2
#define HWCAP_CMOV  4
#define HWCAP_UNICORE_F64  8
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
/*
* This yields a mask that user programs can use to figure out what
* instruction set this cpu supports.
*/
#define ELF_HWCAP (elf_hwcap)
extern unsigned int elf_hwcap;
#endif
#endif


文件 asm/ptrace.h
/*
* linux/arch/unicore/include/asm/ptrace.h
*
* Code specific to PKUnity SoC and UniCore ISA
* Fragments that appear the same as the files in arm or x86
*
* Copyright (C) 2001-2008 GUAN Xue-tao
*
* 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.
*/
#ifndef __UNICORE_PTRACE_H__
#define __UNICORE_PTRACE_H__
#include <asm/hwcap.h>
#define PTRACE_GETREGS  12
#define PTRACE_SETREGS  13
#define PTRACE_GETFPREGS  14
#define PTRACE_SETFPREGS  15
/* PTRACE_ATTACH is   16 */
/* PTRACE_DETACH is   17 */
/* 18~20 is unused */
#define PTRACE_OLDSETOPTIONS   21
#define PTRACE_GET_THREAD_AREA  22
#define PTRACE_SET_SYSCALL   23
/* PTRACE_SYSCALL is   24 */
#define PTRACE_GETVFPREGS   27
#define PTRACE_SETVFPREGS   28
/*
* PSR bits
*/
#define USER_MODE 0x00000010
#define REAL_MODE 0x00000011
#define INTR_MODE 0x00000012
#define PRIV_MODE  0x00000013
#define ABRT_MODE 0x00000017
#define EXTN_MODE 0x0000001b
#define SUSR_MODE 0x0000001f
#define MODE_MASK 0x0000001f
#define PSR_R_BIT 0x00000040
#define PSR_I_BIT 0x00000080
#define PSR_V_BIT0x10000000
#define PSR_C_BIT 0x20000000
#define PSR_Z_BIT 0x40000000
#define PSR_S_BIT 0x80000000
/*
* Groups of PSR bits
*/
#define PSR_f  0xff000000  /* Flags*/
#define PSR_s  0x00ff0000  /* Status*/
#define PSR_x  0x0000ff00  /* Extension*/ 
#define PSR_c  0x000000ff  /* Control*/

/*
* These are 'magic' values for PTRACE_PEEKUSR that return info about where a
* process is located in memory.
*/
#define PT_TEXT_ADDR  0x10000
#define PT_DATA_ADDR  0x10004
#define PT_TEXT_END_ADDR   0x10008
#ifndef __ASSEMBLY__
/*
* This struct defines the way the registers are stored on the
* stack during a system call. Note that sizeof(struct pt_regs)
* has to be a multiple of 8.
*/
struct pt_regs {
long uregs[34];
};
#define UCreg_csr  uregs[32]
#define UCreg_pc  uregs[31]
#define UCreg_lr  uregs[30]
#define UCreg_sp  uregs[29]
#define UCreg_ip  uregs[28]
#define UCreg_fp  uregs[27]
#define UCreg_26  uregs[26]
#define UCreg_25  uregs[25]
#define UCreg_24  uregs[24]
#define UCreg_23  uregs[23]
#define UCreg_22  uregs[22]
#define UCreg_21  uregs[21]
#define UCreg_20  uregs[20]
#define UCreg_19  uregs[19]
#define UCreg_18  uregs[18]

#define UCreg_17  uregs[17]
#define UCreg_16  uregs[16]
#define UCreg_15  uregs[15]
#define UCreg_14  uregs[14]
#define UCreg_13  uregs[13]
#define UCreg_12  uregs[12]
#define UCreg_11  uregs[11]
#define UCreg_10  uregs[10]
#define UCreg_09  uregs[9]
#define UCreg_08  uregs[8]
#define UCreg_07  uregs[7]
#define UCreg_06  uregs[6]
#define UCreg_05  uregs[5]
#define UCreg_04  uregs[4]
#define UCreg_03  uregs[3]
#define UCreg_02  uregs[2]
#define UCreg_01  uregs[1]
#define UCreg_00  uregs[0]
#define UCreg_ORIG_00  uregs[33]
#ifdef __KERNEL__
#define user_mode(regs) \
  (processor_mode(regs) == USER_MODE)
#define isa_mode(regs)
  0
#define processor_mode(regs) \
  ((regs)->UCreg_csr & MODE_MASK)
#define interrupts_enabled(regs) \
  (!((regs)->UCreg_csr & PSR_I_BIT))
#define fast_interrupts_enabled(regs) \
  (!((regs)->UCreg_csr & PSR_R_BIT))
/* Are the current registers suitable for user mode?
* (used to maintain security in signal handlers)
*/
static inline int valid_user_regs(struct pt_regs *regs)
{
  if (user_mode(regs) && (regs->UCreg_csr & PSR_I_BIT) == 0) {
    regs->UCreg_csr &= ~(PSR_R_BIT);
    return 1;
  }
/*
* Force CSR to something logical...
*/
  regs->UCreg_csr &= PSR_f | PSR_s | PSR_x | USER_MODE;
  return 0;
}
#define instruction_pointer(regs)  (regs)->UCreg_pc
#define profile_pc(regs) instruction_pointer(regs)
#define predicate(x)  ((x) & 0xf0000000)
#define PREDICATE_ALWAYS  0xe0000000
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
#endif


文件 asm/assember.h
/*
* linux/arch/unicore/include/asm/assembler.h
*
* Code specific to PKUnity SoC and UniCore ISA
* Fragments that appear the same as the files in arm or x86
*
* Copyright (C) 2001-2008 GUAN Xue-tao
*
* 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.
*
* Do not include any C declarations in this file - it is included by
* assembler source.
*/
#ifndef __ASSEMBLY__
#error "Only include this from assembly code"
#endif
#include <asm/ptrace.h>
/*
* Little Endian independent macros for shifting bytes within registers.
*/
#define pull  >>
#define push  <<
#define get_byte_0  << #0
#define get_byte_1   >> #8
#define get_byte_2   >> #16
#define get_byte_3   >> #24
#define put_byte_0  << #0
#define put_byte_1   << #8
#define put_byte_2   << #16
#define put_byte_3   << #24
/*
* Enable and disable interrupts
*/
.macro disable_irq_notrace, temp
  mov \temp, asr
  andn \temp, \temp, #0xFF
  or \temp, \temp, #PSR_I_BIT | PRIV_MODE
  mov.a
  asr, \temp
.endm


.macro enable_irq_notrace, temp
  mov \temp, asr
  andn \temp, \temp, #0xFF
  or \temp, \temp, #PRIV_MODE
  mov.a
  asr, \temp
.endm


.macro asm_trace_hardirqs_off
  #if defined(CONFIG_TRACE_IRQFLAGS)
  stm.w (ip, lr), [sp-]
  stm.w (r0-r3), [sp-]
  b.l trace_hardirqs_off
  ldm.w
  (r0-r3), [sp]+
  ldm.w
  (ip, lr), [sp]+
  #endif
.endm


.macro asm_trace_hardirqs_on_cond, cond
  #if defined(CONFIG_TRACE_IRQFLAGS)
/*
* actually the registers should be pushed and pop'd conditionally, but
* after bl the flags are certainly clobbered
*/
  stm.w (ip, lr), [sp-]
  stm.w (r0-r3), [sp-]
  bl\cond trace_hardirqs_on
  ldm.w
  (r0-r3), [sp]+
  ldm.w
  (ip, lr), [sp]+
  #endif
.endm


.macro asm_trace_hardirqs_on
  asm_trace_hardirqs_on_cond al
.endm


.macro disable_irq, temp
  disable_irq_notrace \temp
  asm_trace_hardirqs_off
.endm


.macro enable_irq, temp
  asm_trace_hardirqs_on
  enable_irq_notrace \temp
.endm
/*
* Save the current IRQ state and disable IRQs. Note that this macro
* assumes FIQs are enabled, and that the processor is in SVC mode.
*/
.macro save_and_disable_irqs, oldcpsr, temp
  mov \oldcpsr, asr
  disable_irq \temp
.endm


/*
* Restore interrupt state previously stored in a register. We don't
* guarantee that this will preserve the flags.
*/


.macro restore_irqs_notrace, oldcpsr, temp
  mov \temp, asr
  mov.a
  asr, \oldcpsr
  mov.f
  asr, \temp
.endm


.macro restore_irqs, oldcpsr, temp
  cmpand.a \oldcpsr, #PSR_I_BIT
  asm_trace_hardirqs_on_cond eq
  restore_irqs_notrace \oldcpsr, \temp
.endm


#define USER(x...) \ 

9999:  \

  .section __ex_table,"ax";  \
  .align  3;  \
  .long9999b,9001f;  \
  .previous  \

.macro notcond, cond, nexti=.+8
  .ifc \cond, eq
    bne \nexti
  .else;.ifc \cond, ne
    beq \nexti
  .else;.ifc \cond, ea
    bub \nexti
  .else;.ifc \cond, ub
    bea \nexti
  .else;.ifc \cond, fs
    bns \nexti
  .else;.ifc \cond, ns
    bfs \nexti
  .else;.ifc \cond, fv
    bnv \nexti
  .else;.ifc \cond, nv
    bfv \nexti
  .else;.ifc \cond, ua
    beb \nexti
  .else;.ifc \cond, eb
    bua \nexti
  .else;.ifc \cond, eg
    bsl \nexti
  .else;.ifc \cond, sl
    beg \nexti
  .else;.ifc \cond, sg
    bel \nexti
  .else;.ifc \cond, el
    bsg \nexti
  .else;.ifnc \cond, al
  .error "Unknown cond in notcond macro argument"
 .endif;.endif;.endif;.endif;.endif;.endif;.endif;.endif;.endif;.endif;.endif;.endif;.endif
.endm

.endif
.endif


.macro usracc, instr, reg, ptr, inc, cond, rept, abort
  .rept \rept
  notcond \cond, .+8
9999:
  .if \inc == 1
    \instr\()b.u \reg, [\ptr], #\inc
  .elseif  \inc == 4
    \instr\()w.u \reg, [\ptr], #\inc
  .else
  .error  "Unsupported inc macro argument"
  .endif
  .section __ex_table,"a"
  .align
  3
  .long9999b, \abort
  .previous
  .endr
.endm


.macro strusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
  usracc st, \reg, \ptr, \inc, \cond, \rept, \abort
.endm


.macro ldrusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
  usracc ld, \reg, \ptr, \inc, \cond, \rept, \abort
.endm


文件 asm/linkage.h
/
*
* linux/arch/unicore/include/asm/linkage.h
*
* Code specific to PKUnity SoC and UniCore ISA
* Fragments that appear the same as the files in arm or x86
*
* Copyright (C) 2001-2008 GUAN Xue-tao
*
* 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.
*/
#ifndef __UNICORE_LINKAGE_H__
#define __UNICORE_LINKAGE_H__
#define __ALIGN .align 0
#define __ALIGN_STR ".align 0"
#define ENDPROC(name) \
.type name, %function; \
END(name)
#endif


文件 linux/linkage.h
#ifndef _LINUX_LINKAGE_H
#define _LINUX_LINKAGE_H
#include <linux/compiler.h>
#include <asm/linkage.h>
#ifdef __cplusplus
#define CPP_ASMLINKAGE extern "C"
#else
#define CPP_ASMLINKAGE
#endif
#ifndef asmlinkage
#define asmlinkage CPP_ASMLINKAGE
#endif
#ifndef asmregparm
# define asmregparm
#endif
#define __page_aligned_data __section(.data.page_aligned) __aligned(PAGE_SIZE)
#define __page_aligned_bss __section(.bss.page_aligned) __aligned(PAGE_SIZE)
/*
* For assembly routines.
*
* Note when using these that you must specify the appropriate
* alignment directives yourself
*/
#define __PAGE_ALIGNED_DATA
.section ".data.page_aligned", "aw"
#define __PAGE_ALIGNED_BSS .section ".bss.page_aligned", "aw"
/*
* This is used by architectures to keep arguments on the stack
* untouched by the compiler by keeping them live until the end.
* The argument stack may be owned by the assembly-language
* caller, not the callee, and gcc doesn't always understand
* that.
*
* We have the return value, and a maximum of six arguments.
*
* This should always be followed by a "return ret" for the
* protection to work (ie no more work that the compiler might
* end up needing stack temporaries for).
*/
/* Assembly files may be compiled with -traditional .. */
#ifndef __ASSEMBLY__
#ifndef asmlinkage_protect
# define asmlinkage_protect(n, ret, args...)
do { } while (0)
#endif
#endif
#ifndef __ALIGN
#define __ALIGN
.align 4,0x90
#define __ALIGN_STR ".align 4,0x90"
#endif
#ifdef __ASSEMBLY__


#ifndef LINKER_SCRIPT
#define ALIGN __ALIGN
#define ALIGN_STR __ALIGN_STR


#ifndef ENTRY
#define ENTRY(name) \
.globl name; \
ALIGN; \
name:
#endif
#endif /* LINKER_SCRIPT */
#ifndef WEAK
#define WEAK(name)  \
  .weak name;  \
  name:
#endif
#ifndef END
#define END(name) \
.size name, .-name
#endif
/* If symbol 'name' is treated as a subroutine (gets called, and returns)
* then please use ENDPROC to mark 'name' as STT_FUNC for the benefit of
* static analysis tools such as stack depth analyzer.
*/
#ifndef ENDPROC
#define ENDPROC(name) \
.type name, @function; \
END(name)
#endif
#endif
#define NORET_TYPE /**/
#define ATTRIB_NORET __attribute__((noreturn))
#define NORET_AND noreturn,
#endif


文件 lib/copy_from_user.S
/*
* linux/arch/unicore/lib/copy_from_user.S
*
* Code specific to PKUnity SoC and UniCore ISA
* Fragments that appear the same as the files in arm or x86
*
* Copyright (C) 2001-2008 GUAN Xue-tao
*
* 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.
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
/*
* Prototype:
*
* size_t __copy_from_user(void *to, const void *from, size_t n)
*
* Purpose:
*
* copy a block to kernel memory from user memory
*
* Params:
*
* to = kernel memory
* from = user memory
* n = number of bytes to copy
*
* Return value:
*
* Number of bytes NOT copied.
*/
.macro ldr1w ptr reg abort
  ldrusr  \reg, \ptr, 4, abort=\abort
.endm


.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
100: ldm.w  (\reg1, \reg2, \reg3, \reg4), [\ptr]+
  .section __ex_table, "a"
  .align  3
  .long 100b, \abort
  .previous
.endm


.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
100:

   ldm.w  (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+
  .section __ex_table, "a"
  .align  3
  .long 100b, \abort
  .previous
.endm


.macro ldr1b ptr reg cond=al abort
  ldrusr  \reg, \ptr, 1, \cond, abort=\abort
.endm


.macro str1w ptr reg abort
  stw.w \reg, [\ptr]+, #4
.endm


.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
  stm.w  (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+
.endm

.macro str1b ptr reg cond=al abort
  .ifnc \cond, al
  b\cond 201f
  b  202f
  .endif
201:

  stb.w \reg, [\ptr]+, #1
202:
.endm


.macro enter
  mov r3, #0
  stm.w  (r0, r2, r3), [sp-]
.endm


.macro exit
  add sp, sp, #8
  ldm.w  (r0), [sp]+
  mov pc, lr
.endm


.text
ENTRY(__copy_from_user)
#include "copy_template.S"
ENDPROC(__copy_from_user)
  .section .fixup,"ax"
  .align 0
  copy_abort_preamble
  ldm.w  (r1, r2), [sp]+
  sub r3, r0, r1
  rsub r1, r3, r2
  stw r1, [sp]
  b.l __memzero
  ldw.w  r0, [sp]+, #4
  copy_abort_end
  .previous


文件 lib/copy_to_user.S
/*
* linux/arch/unicore/lib/copy_to_user.S
*
* Code specific to PKUnity SoC and UniCore ISA
* Fragments that appear the same as the files in arm or x86
*
* Copyright (C) 2001-2008 GUAN Xue-tao
*
* 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.
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
/*
* Prototype:
*
* size_t __copy_to_user(void *to, const void *from, size_t n)
*
* Purpose:
*
* copy a block to user memory from kernel memory
*
* Params:
*
* to = user memory
* from = kernel memory
* n = number of bytes to copy
*
* Return value:
*
* Number of bytes NOT copied.
*/
.macro ldr1w ptr reg abort
ldw.w \reg, [\ptr]+, #4
.endm


.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
ldm.w  (\reg1, \reg2, \reg3, \reg4), [\ptr]+
.endm


.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
ldm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+
.endm


.macro ldr1b ptr reg cond=al abort
  notcond \cond, .+8
  ldb.w \reg, [\ptr]+, #1
.endm


.macro str1w ptr reg abort
  strusr  \reg, \ptr, 4, abort=\abort
.endm


.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
100:

  stm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+
  .section __ex_table, "a"
  .long 100b, \abort
  .previous
.endm


.macro str1b ptr reg cond=al abort
  strusr  \reg, \ptr, 1, \cond, abort=\abort
.endm


.macro enter
  mov r3, #0
  stm.w  (r0, r2, r3), [sp-]
.endm
  .macro exit
  add sp, sp, #8
  ldm.w  (r0), [sp]+
  mov pc, lr
.endm


.text
ENTRY(__copy_to_user_std)
WEAK(__copy_to_user)
#include "copy_template.S"
ENDPROC(__copy_to_user)
  .section .fixup,"ax"
  .align 0
  copy_abort_preamble
  ldm.w  (r1, r2, r3), [sp]+
  sub r0, r0, r1
  rsub r0, r0, r2
  copy_abort_end
  .previous


文件 lib/copy_template.S
/*
* linux/arch/unicore/lib/copy_template.S
*
* Code specific to PKUnity SoC and UniCore ISA
* Fragments that appear the same as the files in arm or x86
*
* Copyright (C) 2001-2008 GUAN Xue-tao
*
* 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.
*/
/*
* Theory of operation
* -------------------
*
* This file provides the core code for a forward memory copy used in
* the implementation of memcopy(), copy_to_user() and copy_from_user().
*
* The including file must define the following accessor macros
* according to the need of the given function:
*
* ldr1w ptr reg abort
*
* This loads one word from 'ptr', stores it in 'reg' and increments
* 'ptr' to the next word. The 'abort' argument is used for fixup tables.
*
* ldr4w ptr reg1 reg2 reg3 reg4 abort
* ldr8w ptr, reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
*
* This loads four or eight words starting from 'ptr', stores them
* in provided registers and increments 'ptr' past those words.
* The'abort' argument is used for fixup tables.
*
* ldr1b ptr reg cond abort
*
* Similar to ldr1w, but it loads a byte and increments 'ptr' one byte.
* It also must apply the condition code if provided, otherwise the
* "al" condition is assumed by default.
*
* str1w ptr reg abort
* str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
* str1b ptr reg cond abort
*
* Same as their ldr* counterparts, but data is stored to 'ptr' location
* rather than being loaded.
*
* enter
*
* Preserve the provided registers on the stack plus any additional
* data as needed by the implementation including this code. Called
* upon code entry.
*
* exit
*
* Restore registers with the values previously saved with the
* 'preserv' macro. Called upon code termination.
*/
enter
  sub.ar2, r2, #4
  bsl 8f
  and.a
  ip, r0, #3
  bne 9f
  and.a
  ip, r1, #3
  bne 10f
  1:sub.ar2, r2, #(28)
  stm.w  (r5 - r8), [sp-]
  bsl 5f

3:

4:

  ldr8w  r1, r3, r4, r5, r6, r7, r8, r10, r11, abort=20f
  sub.ar2, r2, #32
  str8w  r0, r3, r4, r5, r6, r7, r8, r10, r11, abort=20f
  beg 3b

5:
  and.a
  ip, r2, #28
  rsub ip, ip, #32
  beq 7f
  add pc, pc, ip  @ C is always clear here
  nop
  ldr1w  r1, r3, abort=20f
  ldr1w  r1, r4, abort=20f
  ldr1w  r1, r5, abort=20f
  ldr1w  r1, r6, abort=20f
  ldr1w  r1, r7, abort=20f
  ldr1w  r1, r8, abort=20f
  ldr1w  r1, r11, abort=20f
  add pc, pc, ip
  nop
  str1w  r0, r3, abort=20f
  str1w  r0, r4, abort=20f
  str1w  r0, r5, abort=20f
  str1w  r0, r6, abort=20f
  str1w  r0, r7, abort=20f
  str1w  r0, r8, abort=20f
  str1w  r0, r11, abort=20f
7:

  ldm.w  (r5 - r8), [sp]+
8:

  mov.a  r2, r2 << #31
   ldr1b  r1, r3, ne, abort=21f
  ldr1b  r1, r4, ea, abort=21f
  ldr1b  r1, r10, ea, abort=21f
  str1b r0, r3, ne, abort=21f
  str1b r0, r4, ea, abort=21f
  str1b r0, r10, ea, abort=21f
  exit
9:

  rsub ip, ip, #4
   cmpsub.a ip, #2
   ldr1b  r1, r3, sg, abort=21f
  ldr1b  r1, r4, eg, abort=21f
  ldr1b  r1, r11, abort=21f
  str1b r0, r3, sg, abort=21f
  str1b r0, r4, eg, abort=21f
  sub.ar2, r2, ip
  str1b r0, r11, abort=21f
  bsl 8b
  and.a  ip, r1, #3
  beq 1b
10:

  andn r1, r1, #3

  cmpsub.a ip, #2
    ldr1w   r1, r11, abort=21f
  beq 17f
  bsg 18f
.macro
  forward_copy_shift a b
  sub.ar2, r2, #28
  bsl 14f
11:
  stm.w  (r5 - r9), [sp-]
12:
  ldr4w  r1, r4, r5, r6, r7, abort=19f
  mov r3, r11 pull #\a
  sub.ar2, r2, #32
  ldr4w  r1, r8, r9, r10, r11, abort=19f
  or r3, r3, r4 push #\b
  mov r4, r4 pull #\a
  or r4, r4, r5 push #\b
  mov r5, r5 pull #\a
  or r5, r5, r6 push #\b
  mov r6, r6 pull #\a
  or r6, r6, r7 push #\b
  mov r7, r7 pull #\a
  or r7, r7, r8 push #\b
  mov r8, r8 pull #\a
  or r8, r8, r9 push #\b
  mov r9, r9 pull #\a
  or r9, r9, r10 push #\b
  mov r10, r10 pull #\a
  or r10, r10, r11 push #\b
  str8w  r0, r3, r4, r5, r6, r7, r8, r9, r10, , abort=19f
  beg 12b  

  ldm.w  (r5 - r9), [sp]+
14:

  and.a   ip, r2, #28
    beq 16f
15:

  mov r3, r11 pull #\a
  ldr1w  r1, r11, abort=21f
      sub.aip, ip, #4
  or r3, r3, r11 push #\b
  str1w  r0, r3, abort=21f
  bsg 15b
16:

  sub r1, r1, #(\b / 8)
      b  8b
.endm
  forward_copy_shift a=8 b=24
17: forward_copy_shift a=16b=16
18: forward_copy_shift a=24b=8
/*
* Abort preamble and completion macros.
* If a fixup handler is required then those macros must surround it.
* It is assumed that the fixup code will handle the private part of
* the exit macro.
*/
.macro copy_abort_preamble
19:

  ldm.w  (r5 - r9), [sp]+
  b  21f
299:

  .word  0  @ store lr, to avoid function call in fixup
20:

  ldm.w  (r5 - r8), [sp]+
21:
  adr r1, 299b
  stw lr, [r1]
.endm


.macro copy_abort_end
  adr lr, 299b
  ldw pc, [lr]
.endm


文件 lib/memcpy.S
/*
* linux/arch/unicore/lib/memcpy.S
*
* Code specific to PKUnity SoC and UniCore ISA
* Fragments that appear the same as the files in arm or x86
*
* Copyright (C) 2001-2008 GUAN Xue-tao
*
* 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.
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
.macro ldr1w ptr reg abort
  ldw.w \reg, [\ptr]+, #4
.endm


.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
  ldm.w (\reg1, \reg2, \reg3, \reg4), [\ptr]+
.endm


.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
  ldm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+
.endm


.macro ldr1b ptr reg cond=al abort
  .ifnc \cond, al
  b\cond 201f
  b  202f
  .endif
201:

  ldb.w \reg, [\ptr]+, #1
202:
.endm


.macro str1w ptr reg abort
  stw.w \reg, [\ptr]+, #4
.endm


.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
  stm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+
.endm


.macro str1b ptr reg cond=al abort
  .ifnc \cond, al
  b\cond 201f
  b  202f
.endif


201:

  stb.w \reg, [\ptr]+, #1
202:
.endm


.macro enter
  stm.w (r0), [sp-]
.endm


.macro exit
  ldm.w (r0), [sp]+
  mov pc, lr
.endm


.text
/* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
ENTRY(memcpy)
  #include "copy_template.S"
ENDPROC(memcpy)

原文地址:https://www.cnblogs.com/openix/p/2531323.html