Uboot的start.s源码分析

/*

 *  armboot - Startup Code for ARM920 CPU-core

 *

 *  Copyright (c) 2001 Marius Gr鰃er <mag@sysgo.de>

 *  Copyright (c) 2002 Alex Z黳ke <azu@sysgo.de>

 *  Copyright (c) 2002 Gary Jennejohn <gj@denx.de>

 *

 * See file CREDITS for list of people who contributed to this

 * project.

 *

 * This program is free software; you can redistribute it and/or

 * modify it under the terms of the GNU General Public License as

 * published by the Free Software Foundation; either version 2 of

 * the License, or (at your option) any later version.

 *

 * This program is distributed in the hope that it will be useful,

 * but WITHOUT ANY WARRANTY; without even the implied warranty of

 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

 * GNU General Public License for more details.

 *

 * You should have received a copy of the GNU General Public License

 * along with this program; if not, write to the Free Software

 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,

 * MA 02111-1307 USA

 */

#include <config.h>

#include <version.h>

/*

 *************************************************************************

 *

 * Jump vector table as in table 3.1 in [1]

start.s代码,是u-boot的stage1阶段所要运行的代码

由于一个可执行的Image必须有一个入口点,并且只能有一个全局入口,通常这个入口放在ROM(flash)的0x地址。因此,必须通知编译器以使其知道这个入口,该工作可以通过修改连接器的脚本来完成。

  1. board/smdk2410/uboot.lds:  ENTRY(_start)==>cpu/arm920t/start.o(.text)
  2. Uboot在ram的代码区(TEXT_BASE=0X33F80000)定义在board/amdk2410/config.mk

***********************************************************************

 */

/*

.globl symbol

定义一个全局符号,让这个符号对链接器可见,通常为连接器(ld)使用。symbol是全局可见的,可以供其他链接对象模块使用。

.global _start 让 _start 符号成为可见的标识符,这样链接器就知道跳转到程序中的什么地方并开始执行。linux寻找这个 _start 标签作为程序的默认进入点。标号_start是GNU链接器用来指定第一个要执行指令所必须的,同样的是全局可见的(并且只能出现在一个模块中)。

标号是后边紧跟一个冒号的符号,此时该标号代表活动位置计数器的当前值,并且可作为指令的操作数使用。
*/

.globl _start

_start: b       reset                 /*reset异常不返回,下边都是异常跳转地址*/

ldr pc, _undefined_instruction

ldr pc, _software_interrupt

ldr pc, _prefetch_abort

ldr pc, _data_abort

ldr pc, _not_used

ldr pc, _irq

ldr pc, _fiq

/*

.globl _start 、 _start: 这些伪指令,标号在编译后的代码中并不占用内存。

Ldr 加载指定存储器地址中的内容到寄存器,区分:ldr伪指令

当发生异常时,执行cpu/arm920t/interrupts.c中的中断处理函数

.word expressions :定义一个字,并为之分配空间,4bytes。同理有:

.short expressions/.int expressions/.byte expressions/.long expressions/.ascii "string"

原理分析:在这里先预留好空间,空间里边的内容就是后边的expression,这里expression是标号,则代表的是某个地址,该地址就是异常处理函数的首地址。

当发生某异常时,处理器自动跳到存储器起始的对应异常处理地址(由硬件确定地址,即地址的前几个字,见上代码),执行里边的代码,里边一般都放置一个跳转指令。如:ldr pc, _undefined_instruction ;将此标号地址处的内容取出来给pc指针,而这内容恰好是异常处理函数的首地址(预留的空间就是为了放异常处理地址用的,这里_software_interrupt: .word software_interrupt指令中software_interrupt,是一个标号,标号代表的是处理地址,也是跳转的目标地址,该标号在本文件最下边有定义,其他标号类似),这样完成了一次异常处理。

见图示更易理解:

  地址      地址中内容     指令内容

*/

_undefined_instruction: .word undefined_instruction

_software_interrupt: .word software_interrupt

_prefetch_abort: .word prefetch_abort

_data_abort: .word data_abort

_not_used: .word not_used

_irq: .word irq

_fiq: .word fiq

.balignl 16,0xdeadbeef

/*

这是一个数据对齐指令,在这个.balignl 16,0xdeadbeef指令之前,一共占了4x15=60个字节的内存,15个字。所以本代码的作者当时就简单的在15这个数上,加了个1,即16,把当前指针往后移到地址为64的位置,然后在前面插上了0xdeadbeef这个特殊的值。见图示中0x0000003c位置的内容。详细解释见《于关u-boot中的.balignl 16,0xdeadbeef的理解》一文。

*/

/*

 *************************************************************************

 *

 * Startup Code (reset vector)

 *

 * do important init only if we don't start from memory!

 * relocate armboot to ram

 * setup stack

 * jump to second stage

 *

 *************************************************************************

 */

_TEXT_BASE:

.word TEXT_BASE

.globl _armboot_start

_armboot_start:

.word _start

/*

 * These are defined in the board-specific linker script.

 */

.globl _bss_start

_bss_start:

.word __bss_start

.globl _bss_end

_bss_end:

.word _end

#ifdef CONFIG_USE_IRQ

/* IRQ stack memory (calculated at run-time) */

.globl IRQ_STACK_START

IRQ_STACK_START:

.word 0x0badc0de

/* IRQ stack memory (calculated at run-time) */

.globl FIQ_STACK_START

FIQ_STACK_START:

.word 0x0badc0de

#endif

/*

 * the actual reset code

 */

reset:

/*

 * set the cpu to SVC32 mode

刚进入系统时,设置为管理模式

CPSR_c或SPSR_c的位示意图(控制位:低8位):

7  6  5   4   3   2   1   0

I  F  T  M4  M3  M2  M1  M0

I:IRQ禁止,1禁止,0允许

F:FIQ禁止,1禁止,0允许

T:状态位,0-ARM,1-Thumb

M4-M0:模式位

10000-用户,10001-快速中断,10010-中断,10011-管理,10111-未定义,11111-系统

 */

mrs r0,cpsr

bic r0,r0,#0x1f

orr r0,r0,#0xd3

msr cpsr,r0

/* turn off the watchdog */

/*这些寄存器的地址,根据不同的芯片有不同配置,具体用到时,要更改*/

#if defined(CONFIG_S3C2400)

# define pWTCON 0x15300000

# define INTMSK 0x14400008 /* Interupt-Controller base addresses */

# define CLKDIVN 0x14800014 /* clock divisor register */

#elif defined(CONFIG_S3C2410) /*这是S3C2410的寄存器地址*/

# define pWTCON 0x53000000

# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */

# define INTSUBMSK 0x4A00001C

# define CLKDIVN 0x4C000014 /* clock divisor register */

#endif

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)

ldr     r0, =pWTCON     /*这是个ldr伪指令,将pWTCON所代表的32值给r0寄存器*/

mov     r1, #0x0

str     r1, [r0]

/*

* mask all IRQs by setting all bits in the INTMR - default

*/

ldr r0, =INTMSK

mov r1, #0xffffffff

str r1, [r0]

# if defined(CONFIG_S3C2410)

ldr r1, =0x3ff

ldr r0, =INTSUBMSK

str r1, [r0]

# endif  /*CONFIG_S3C2410*/

/* FCLK:HCLK:PCLK = 1:2:4 */

/* default FCLK is 120 MHz ! */

ldr r0, =CLKDIVN

mov r1, #3

str r1, [r0]

#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */

/*

 * we do sys-critical inits only at reboot,

 * not when booting from ram!

 */

/*

cpu_init_crit代码的主要工作是:禁止MMU,以及指令cache和数据cache,因为uboot在开始时,需要用到物理地址,不能是虚拟地址。故禁止MMU.关闭cache,是为了uboot在写入数据的时候,一定要实实在在的写到物理地址上,而不是写到缓存中。顺便再跳转到lowlevel_init.s中,进行sdram的初始化,为以后拷贝代码做好准备

*/

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

bl cpu_init_crit

#endif

#ifndef CONFIG_SKIP_RELOCATE_UBOOT

relocate: /* relocate U-Boot to RAM     */

adr r0, _start /* r0 <- current position of code   */

ldr r1, _TEXT_BASE /* test if we run from flash or RAM */

cmp     r0, r1                  /* don't reloc during debug         */

beq     stack_setup

/*

bss段的开始地址,就是代码段的结束地址:_bss_start-_armboot_start=size of data

关于_start 和_TEXT_BASE之间的关系,还有虚拟地址,物理地址在此处的分配,还有待以后研究。

注意:此处的源代码,并没有涉及从nand flash 拷贝数据到ram中,如果需要移植的话,要自己写nand flash的驱动函数,并且拷贝数据到ram中。

*/

ldr r2, _armboot_start

ldr r3, _bss_start

sub r2, r3, r2 /* r2 <- size of armboot            */

add r2, r0, r2 /* r2 <- source end address         */

/*

这个循环拷贝,是从nor flash 中拷贝数据到ram中,并不是从nand flash拷贝数据,nor flash的操作类似于ram,直接操作地址总线,数据总线即可。Nand flash却不可以,需要一定的操作时序和驱动。直白一点:nor flash类似于ram,可以直接跟cpu的数据、控制、地址总线连接,进行控制;nand flash 不可以,有时序限制,需要驱动。

*/

copy_loop:

ldmia r0!, {r3-r10} /* copy from source address [r0]    */

stmia r1!, {r3-r10} /* copy to   target address [r1]    */

cmp r0, r2 /* until source end addreee [r2]    */

ble copy_loop

#endif /* CONFIG_SKIP_RELOCATE_UBOOT */

/*

 Set up the stack

分析:建立栈空间的过程

Ram中的地址分布(高->低):...,bss区,u-boot镜像,CFG_MALLOC_LEN,GBL_DATA_SIZE,

IRQ&FIQ栈区(可选,视具体情况),用户栈区(向下生长,sp指针初始位置),SDRAM_BASE。_TEXT_BASE并不是ram中的起始地址,只是u-boot放置的首地址,源码中是:0x33f80000。

    */

stack_setup:

ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot   */

sub r0, r0, #CFG_MALLOC_LEN /* malloc area                      */

sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */

#ifdef CONFIG_USE_IRQ

sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

sub sp, r0, #12 /* leave 3 words for abort-stack    */

/*

借此详细分析:编译器跟代码的交互原理

在ads编译程序代码的时候,会要求我们输入程序的入口代码地址,开始执行地址,各个段的存放首地址(基本由编译器自己根据代码大小情况决定,但我们可以自己指定,虽然一般不这么做)等信息。

类似,在用交叉编译器,编译我们的bootloader代码时,它们也会用到这些地址。不过一般由编译器自己指定一部分(如:__bss_start),我们指定一部分必要的(如:TEXT_BASE,一般放在某些配置文件里边,供编译器查看)。

我们看看由编译器自己指定的情况:

.globl _bss_start

_bss_start:

.word __bss_start

定义一个全局标号_bss_start,标号代表该地址,在该地址处定义了一个字大小的变量,变量内容是__bss_start,而这个__bss_start是由编译器在编译代码时确定的,由编译器把该变量的值填入此位置,供其他代码使用。

__bss_start:应该是编译器内部定义好的变量,专用的。

*/

clear_bss:

ldr r0, _bss_start /* find start of bss segment        */

ldr r1, _bss_end /* stop here                        */

mov r2, #0x00000000 /* clear                            */

clbss_l:str r2, [r0] /* clear loop...                    */

add r0, r0, #4

cmp r0, r1

ble clbss_l

/*这一段代码默认是不编译的,也就是寄存器设置,和时钟设置,参考datasheet就可以*/

#if 0

/* try doing this stuff after the relocation */

ldr     r0, =pWTCON

mov     r1, #0x0

str     r1, [r0]

/*

 * mask all IRQs by setting all bits in the INTMR - default

 */

mov r1, #0xffffffff

ldr r0, =INTMR

str r1, [r0]

/* FCLK:HCLK:PCLK = 1:2:4 */

/* default FCLK is 120 MHz ! */

ldr r0, =CLKDIVN

mov r1, #3

str r1, [r0]

/* END stuff after relocation */

#endif

ldr pc, _start_armboot

_start_armboot: .word start_armboot

/*

 *************************************************************************

 *

 * CPU_init_critical registers

 *

 * setup important registers

 * setup memory timing

 *

 *************************************************************************

 */

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

cpu_init_crit:

/*

以下指令时对协处理器进行操作:cp15

 * flush v4 I/D caches

mcr p15, 0, r0, c7, c7, 0;这一句的意思是:使指令cache和数据cache失效,即:关闭

这一句的具体含义见《arm920t technical reference manual》手册,里边也并未给出具体含义,只是写出了某些操作时需要用到的命令。

mcr p15, 0, r0, c8, c7, 0;关闭指令tlb和数据tlb,文档也只是列出了五个相关指令。

 */

mov r0, #0

mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */

mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */

/*

 * disable MMU stuff and caches

协处理器中register 1是control register

13:V bit  function:base location of exception registers(异常寄存器的基地址)

          0=low address=0x00000000;1=high address=0xffff0000

12: I bit Icache enable ,0=Icache disabled,1=Icache enabled

 9:R bit  ROM protection,this bit modifies the MMU protection system

 8: S bit system protection ,this bit modifies the MMU protection system

 7: B bit endianness ,0=little-endian operation  1=big-endian operation

 2: C bit Dcache enable ,0=Dcache disabled,1=Dcache enabled

 1: A bit Alignment fault enable,Data address alignment fault checking

0=fault checking disabled, 1=fault checking enabled

 0: M bit MMU enable  0=MMU disabled,1=MMU enabled

 */

mrc p15, 0, r0, c1, c0, 0

bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)

bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)

orr r0, r0, #0x00000002 @ set bit 1 (A) Align

orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache

mcr p15, 0, r0, c1, c0, 0

/*

 * before relocating, we have to setup RAM timing

 * because memory timing is board-dependend, you will

 * find a lowlevel_init.S in your board directory.

 */

/*

 r12 是内部调用暂时寄存器 ip。它在过程链接胶合代码(例如,交互操作胶合代码)中用于此角色。在过程调用之间,可以将它用于任何用途。被调用函数在返回之前不必恢复 r12。

ip就是r12寄存器的别名,arm和thumb子程序调用使用规则ATPCS,定义了这些内容。

Reg    APCS   意义
R0      a1   工作寄存器
R1     a2 "
R2   a3 "
R3 a4 "
R4  v1 必须保护
R5 v2 "
R6 v3 "
R7 v4 "
R8 v5 "
R9 v6 "
R10  sl 栈限制
R11  fp 桢指针
R12  ip   
R13  sp  栈指针
R14  lr 连接寄存器
R15  pc 程序计数器

译注:ip 是指令指针的简写。

注意:千万不要把ip和pc两个寄存器混淆了,ip=r12,pc=r15

*/

mov ip, lr //保存子程序返回地址,放到r12中。

bl lowlevel_init //初始化内存配置

mov lr, ip

mov pc, lr

#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

/*

 *************************************************************************

 *

 * Interrupt handling

 *从这里往下,是中断处理函数的调用,一般在uboot中,不会运行到此,uboot中禁用了irq和fiq中断。其他中断应该可以,但一般不会进入。

在此,因为还对编译器中组织的代码不太熟悉,能看懂基本功能即可,不深入追究。等以后再来深入分析原理。

 *************************************************************************

 */

@

@ IRQ stack frame.

@

#define S_FRAME_SIZE 72

#define S_OLD_R0 68

#define S_PSR 64

#define S_PC 60

#define S_LR 56

#define S_SP 52

#define S_IP 48

#define S_FP 44

#define S_R10 40

#define S_R9 36

#define S_R8 32

#define S_R7 28

#define S_R6 24

#define S_R5 20

#define S_R4 16

#define S_R3 12

#define S_R2 8

#define S_R1 4

#define S_R0 0

#define MODE_SVC 0x13

#define I_BIT  0x80

/*

 * use bad_save_user_regs for abort/prefetch/undef/swi ...

 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling

 */

.macro bad_save_user_regs

sub sp, sp, #S_FRAME_SIZE

stmia sp, {r0 - r12} @ Calling r0-r12

ldr r2, _armboot_start

sub r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)

sub r2, r2, #(CFG_GBL_DATA_SIZE+8)  @ set base 2 words into abort stack

ldmia r2, {r2 - r3} @ get pc, cpsr

add r0, sp, #S_FRAME_SIZE @ restore sp_SVC

add r5, sp, #S_SP

mov r1, lr

stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr

mov r0, sp

.endm

.macro irq_save_user_regs

sub sp, sp, #S_FRAME_SIZE

stmia sp, {r0 - r12} @ Calling r0-r12

add     r8, sp, #S_PC

stmdb   r8, {sp, lr}^                   @ Calling SP, LR

str     lr, [r8, #0]                    @ Save calling PC

mrs     r6, spsr

str     r6, [r8, #4]                    @ Save CPSR

str     r0, [r8, #8]                    @ Save OLD_R0

mov r0, sp

.endm

.macro irq_restore_user_regs

ldmia sp, {r0 - lr}^ @ Calling r0 - lr

mov r0, r0

ldr lr, [sp, #S_PC] @ Get PC

add sp, sp, #S_FRAME_SIZE

subs pc, lr, #4 @ return & move spsr_svc into cpsr

.endm

.macro get_bad_stack

ldr r13, _armboot_start @ setup our mode stack

sub r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)

sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack

str lr, [r13] @ save caller lr / spsr

mrs lr, spsr

str     lr, [r13, #4]

mov r13, #MODE_SVC @ prepare SVC-Mode

@ msr spsr_c, r13

msr spsr, r13

mov lr, pc

movs pc, lr

.endm

.macro get_irq_stack @ setup IRQ stack

ldr sp, IRQ_STACK_START

.endm

.macro get_fiq_stack @ setup FIQ stack

ldr sp, FIQ_STACK_START

.endm

/*

 * exception handlers

 */

.align  5

undefined_instruction:

get_bad_stack

bad_save_user_regs

bl do_undefined_instruction

.align 5

software_interrupt:

get_bad_stack

bad_save_user_regs

bl do_software_interrupt

.align 5

prefetch_abort:

get_bad_stack

bad_save_user_regs

bl do_prefetch_abort

.align 5

data_abort:

get_bad_stack

bad_save_user_regs

bl do_data_abort

.align 5

not_used:

get_bad_stack

bad_save_user_regs

bl do_not_used

#ifdef CONFIG_USE_IRQ

.align 5

irq:

get_irq_stack

irq_save_user_regs

bl do_irq

irq_restore_user_regs

.align 5

fiq:

get_fiq_stack

/* someone ought to write a more effiction fiq_save_user_regs */

irq_save_user_regs

bl do_fiq

irq_restore_user_regs

#else

.align 5

irq:

get_bad_stack

bad_save_user_regs

bl do_irq

.align 5

fiq:

get_bad_stack

bad_save_user_regs

bl do_fiq

#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/438694.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微软首批 AI PC 产品将于3月21日发布;腾讯、字节再战 AI 社交产品

微软首批 AI PC 产品将于 3 月 21 日发布 据 Windows Central 报道&#xff0c;微软将于 3 月 21 日发布 Surface Pro 10 和 Surface Laptop 6&#xff0c;这有望成为微软首批 AI PC 产品&#xff0c;性能与效率或可媲美苹果 iPad Pro 和 MacBook Pro。 新品将搭载基于英特尔酷…

OpenHarmony教程指南—Ability的启动模式

介绍 本示例展示了在一个Stage模型中&#xff0c;实现standard、singleton、specified多种模式场景。 本实例参考开发指南 。 本实例需要使用aa工具 查看应用Ability 模式信息。 效果预览 使用说明 1、standard模式&#xff1a; 1&#xff09;进入首页&#xff0c;点击番茄…

arm系统构建的基础知识

目录 一、环境变量 二、归档和压缩 (一) 常用命令 (二) 常用参数 三、磁盘分区和挂载 四、网络管理 一、环境变量 显示环境变量 —— echo设置临时环境变量 —— exportecho $PATH —— 显示当前PATH环境变量 在当前目录下&#xff0c;编写一个hello.c 编译并运行。 图…

HTML静态网页成品作业(HTML+CSS)——花主题介绍网页设计制作(1个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有1个页面。 二、作品演示 三、代…

免费实时天气预报api接口

5分钟更新一次,包含基本天气信息、24小时逐小时天气、实时气象预警列表、湿度、能见度、气压、日出日落、9大生活指数、pm2.5、pm10、o3、no2、so2、是否需要带口罩、外出适宜、开窗适宜、是否需要打开净化器等,可按地名、城市编号、IP查询。 新增:优化预警字段, 返回实时预…

16、电源管理入门之驱动Runtime PM管理

目录 1. 框架介绍 1.1 为什么需要Runtime PM Framework? 1.2 系统框架图 2. Drivers 3. Runtime PM core 4. power domain framework 5. runtime pm的sysfs 6参考: Runtime PM管理也就是设备驱动里面的电源管理,即设备驱动结构体里面的struct dev_pm_ops,只控制设…

Spring Boot 配置热部署

前言 对于 Spring Boot 项目之中, 在刚开始学习的时候, 每当代码进行变动的时候, 想要生效那就必须要手动重启. 为什么要重启呢 ? 原因在于写的代码是依靠运行之后的 class 文件运行的, 当我们的代码更新以后, 如果不去手动重启, 那么就无法生成新的 class 文件, 执行的就是旧…

影响哈默纳科Harmonic减速机使用寿命的5大因素

哈默纳科HarmonicDrive减速机以其轻量、小型、传动效率高、减速范围广、精度高等特点&#xff0c;被广泛应用于各种传动系统中。然而&#xff0c;尽管哈默纳科Harmonic减速机具有诸多优势&#xff0c;但其使用寿命仍可能受到多种因素的影响。 首先&#xff0c;环境因素对哈默纳…

grid布局所有元素在同一行显示且等分列

目录 一、问题 二、实现方式 三、总结 tiips:如嫌繁琐&#xff0c;直接移步总结即可&#xff01; 一、问题 1.grid布局可以通过 grid-template-columns来指定列的宽度。且可以通过repeat来指定重复的次数。但是现在的需求是&#xff1a;grid布局中元素的数量不确定&#…

学生信息管理APP

设计内容简介 本次设计使用Android Studio实现一个学生信息管理系统,系统功能结构如下图所示: 详细设计 数据库设计SQLite,是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低。…

排序算法:插入排序和希尔排序

一、插入排序 1.基本原理 插入排序&#xff08;英语&#xff1a;Insertion Sort&#xff09;是一种简单直观的排序算法。它的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相应位置并插入。插入排序在实现上…

27.基于springboot + vue实现的前后端分离-网上租赁交易系统(项目 + 论文)

项目介绍 本课题是根据用户的需要以及网络的优势建立的一个基于Spring Boot的网上租贸系统&#xff0c;来满足用户网络商品租赁的需求。本网上租贸系统应用Java技术&#xff0c;MYSQL数据库存储数据&#xff0c;基于Spring Boot框架开发。在网站的整个开发过程中&#xff0c;首…

学c++对Python有帮助吗?

学习C对Python编程确实有帮助&#xff0c;尽管这两种语言在许多方面有很大的不同。以下是学习C可能对Python编程产生帮助的几个方面&#xff1a; 理解底层概念&#xff1a;C是一种更接近硬件的编程语言&#xff0c;它要求程序员更深入地理解内存管理、指针、数据类型等底层概念…

linux上安装fastdfs及配置

一、基础环境准备 1、所需软件 名称说明libfastcommonfastdfs分离出的一些公用函数包fastdfsfastdas软件包fastdfs-nginx-modulefastdfst和nginx的关联模块nginxnginxl软件包 2、编辑环境 安装一些基础的支持环境 yum install git gccc gcc-c make automake autoconf libto…

个人项目介绍4:三维园区篇

个人项目介绍: 地图铁路线路篇 地球卫星篇 火车站篇 三维园区篇 项目需求&#xff1a; 1.按比例全景显示三维园区 2.精确显示园区内设备设施 3.实时显示设备报警信息 4.显示园区内摄像监控设备&#xff0c;并可点击显示监控视频流 5.显示园区内的重大危险源和风险分布 …

win 11修改通知显示时间

win11toast&#xff1a;python桌面通知工具-CSDN博客

力扣热题100_普通数组_73_矩阵置零

文章目录 题目链接解题思路解题代码 题目链接 73.矩阵置零 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&…

【金三银四的季节看下Java ORM的走向和性能对比】总结

写在最后 经过将近一周时间的框架收集、学习、实验、编码、测试市面上常见的ORM框架&#xff0c;过程中拜读了很多作者的博文、样例&#xff0c;学习很多收获很多。 重新梳理下整理的框架&#xff1a;mybatis-plus、lazy、sqltoy、mybatis-flex、easy-query、mybatis-mp、jpa、…

Kotlin/Java重写equals后==表现(2)

Kotlin/Java重写equals后表现&#xff08;2&#xff09; 如果不重写默认的equals方法&#xff0c;即使用Object默认的equals()方法&#xff0c;而Object默认的equals方法&#xff0c;其实比较两个对象的地址&#xff1a; fun main(args: Array<String>) {val u1 User(&…

手机app制作商用系统软件开发

手机端的用户占比已经超过了电脑端的用户量&#xff0c;企业想要发展手机端的业务就必须拥有自己的app软件&#xff0c;我们公司就是专门为企业开发手机软件的公司&#xff0c;依据我们多年的开发经验为大家提供在开发app软件的时候怎么选择开发软件的公司。 手机app制…