Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c562fe68c1 | |||
| edd2926aa0 | |||
| 8f9bc3598f | |||
| b9aee7b5e8 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -2,3 +2,6 @@
|
|||||||
*.o
|
*.o
|
||||||
|
|
||||||
a.out
|
a.out
|
||||||
|
|
||||||
|
# Directories
|
||||||
|
output/
|
||||||
|
|||||||
61
02-setjmp/ReadMe.md
Normal file
61
02-setjmp/ReadMe.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
|
||||||
|
|
||||||
|
## 作用
|
||||||
|
setjmp 和 longjmp 可以用来解决以下问题:
|
||||||
|
- 异常处理:在 C 中,缺乏类似 C++ 或其他语言的异常处理机制。setjmp 和 longjmp 提供了模拟异常处理的方式。
|
||||||
|
- 非局部跳转:在复杂的函数调用栈中,可以使用它从深层函数直接跳回到某个点(通常是函数的顶部),以应对错误、资源释放等情况。
|
||||||
|
|
||||||
|
## 示例
|
||||||
|
|
||||||
|
RK3568(ARMv8)平台U-boot引导过程中
|
||||||
|
```assembly
|
||||||
|
#---- u-boot/arch/arm/cpu/armv8/start.S
|
||||||
|
.globl _start
|
||||||
|
_start:
|
||||||
|
b reset
|
||||||
|
|
||||||
|
reset:
|
||||||
|
/* Allow the board to save important registers */
|
||||||
|
b save_boot_params // 弱符号,空实现。Rockchip默认实现(C语言,BROM已完成环境初始化),主要识别:进入下载模式或继续启动
|
||||||
|
.globl save_boot_params_ret // 定义符号(函数) save_boot_params_ret
|
||||||
|
save_boot_params_ret: // 函数 save_boot_params_ret 执行位置
|
||||||
|
...
|
||||||
|
master_cpu:
|
||||||
|
bl _main
|
||||||
|
```
|
||||||
|
```c
|
||||||
|
#---- u-boot/arch/arm/mach-rockchip/bootrom.c
|
||||||
|
/*
|
||||||
|
* All Rockchip BROM implementations enter with a valid stack-pointer,
|
||||||
|
* so this can safely be implemented in C (providing a single
|
||||||
|
* implementation both for ARMv7 and AArch64).
|
||||||
|
*/
|
||||||
|
int save_boot_params(void)
|
||||||
|
int ret = setjmp(brom_ctx); // 设置跳点(并保存环境)
|
||||||
|
|
||||||
|
switch (ret) {
|
||||||
|
case 0: // 下载模式
|
||||||
|
if (check_back_to_brom_dnl_flag()) // 如果需要执行下载,寄存器中的BOOT_BROM_DOWNLOAD位
|
||||||
|
_back_to_bootrom(BROM_BOOT_ENTER_DNL);
|
||||||
|
longjmp(brom_ctx, brom_cmd); // 重走重走switch,此时 ret = BROM_BOOT_ENTER_DNL, 即分支 BROM_BOOT_ENTER_DNL
|
||||||
|
save_boot_params_ret(); // 如果不需要下载,返回 Start.s 中 save_boot_params_ret 位置
|
||||||
|
while (true)
|
||||||
|
/* does not return */;
|
||||||
|
break;
|
||||||
|
case BROM_BOOT_ENTER_DNL:
|
||||||
|
/*
|
||||||
|
* A non-zero return value will instruct the BROM enter
|
||||||
|
* download mode.
|
||||||
|
*/
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
|
...
|
||||||
|
```
|
||||||
|
说明:
|
||||||
|
关键部分:非局部跳转的实现, setjmp 和 longjmp 实现了从特定函数(例如 save_boot_params)的不同执行路径之间的跳转。
|
||||||
|
- 当进入下载模式或跳到下一个启动阶段时,通过 longjmp 可以使程序的控制流根据不同的条件进行相应的跳转。
|
||||||
|
- setjmp 的返回值用于确定当前的跳转状态,并且程序根据该返回值进入不同的处理分支(例如下载模式、下一阶段启动等)。
|
||||||
|
|
||||||
|
局部跳转与非局部跳转的区别
|
||||||
|
- 局部跳转:局部跳转通常发生在同一函数的不同位置之间,常见的例子是 goto 语句,它会跳转到同一个函数内部的其他位置,程序控制流的变化仅限于当前函数。
|
||||||
|
- 非局部跳转:非局部跳转指的是跳转发生在多个函数的调用之间,即跳转目标可能在调用栈的更高层,甚至是跨越多个函数调用。这是 setjmp 和 longjmp 实现的核心功能。
|
||||||
27
02-setjmp/jmp.c
Normal file
27
02-setjmp/jmp.c
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include <setjmp.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
jmp_buf env;
|
||||||
|
|
||||||
|
void second() {
|
||||||
|
printf("Inside second function\n");
|
||||||
|
longjmp(env, 1); // 跳回setjmp的地方,并且setjmp返回1
|
||||||
|
}
|
||||||
|
|
||||||
|
void first() {
|
||||||
|
printf("Inside first function\n");
|
||||||
|
second();
|
||||||
|
printf("This line will not be printed\n"); // 不会执行到这里
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
if (setjmp(env) == 0) {
|
||||||
|
// 第一次调用setjmp时返回0
|
||||||
|
first();
|
||||||
|
} else {
|
||||||
|
// 从longjmp返回时,setjmp将返回非零值
|
||||||
|
printf("Back to main\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
73
03-segfault/Makefile
Normal file
73
03-segfault/Makefile
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#*******************************************************************************
|
||||||
|
# xxx Co., Ltd. All Right Reserved.
|
||||||
|
# Author : yegaoyang@hikvision.com.cn
|
||||||
|
# Version : V1.0.0 202x.xx.xx
|
||||||
|
# Description :
|
||||||
|
# Note :
|
||||||
|
#*******************************************************************************
|
||||||
|
|
||||||
|
#*******************************************************************************
|
||||||
|
# Target name
|
||||||
|
#*******************************************************************************
|
||||||
|
TARGET_NAME = test_segfault
|
||||||
|
|
||||||
|
#*******************************************************************************
|
||||||
|
# Source and oject files
|
||||||
|
#*******************************************************************************
|
||||||
|
OBJS := segfault.o
|
||||||
|
|
||||||
|
#*******************************************************************************
|
||||||
|
# Path information
|
||||||
|
#*******************************************************************************
|
||||||
|
LOCAL_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
|
||||||
|
|
||||||
|
# Subdirectory
|
||||||
|
# Output
|
||||||
|
OUTPUT_DIR := $(LOCAL_DIR)/output
|
||||||
|
INSTALL_DIR ?= $(LOCAL_DIR)/__install
|
||||||
|
#$(info Output directoty : $(OUTPUT_DIR))
|
||||||
|
#$(info Install directoty: $(INSTALL_DIR))
|
||||||
|
|
||||||
|
#*******************************************************************************
|
||||||
|
# Compile configure
|
||||||
|
#*******************************************************************************
|
||||||
|
|
||||||
|
# Toolchain
|
||||||
|
CROSS_COMPILE ?= /home/gaoyang3513/Source/06-SG20x/02-Projects/SDK_SG200x_DuoS/host-tools/gcc/riscv64-linux-musl-x86_64/bin/riscv64-unknown-linux-musl-
|
||||||
|
|
||||||
|
CC := $(CROSS_COMPILE)gcc
|
||||||
|
LD := $(CROSS_COMPILE)ld
|
||||||
|
AR := $(CROSS_COMPILE)ar
|
||||||
|
STRIP := $(CROSS_COMPILE)strip
|
||||||
|
|
||||||
|
# Falgs
|
||||||
|
CFLAGS := -Wall -O2 -DUSER_API -g
|
||||||
|
LDFLAGS := -static
|
||||||
|
ARFLAGS :=
|
||||||
|
|
||||||
|
#*******************************************************************************
|
||||||
|
# Variables
|
||||||
|
#*******************************************************************************
|
||||||
|
MULTI_CORES ?= $(shell grep -c ^processor /proc/cpuinfo)
|
||||||
|
|
||||||
|
#*******************************************************************************
|
||||||
|
# Targets
|
||||||
|
#*******************************************************************************
|
||||||
|
# Specify suffix names and pseudo-targets
|
||||||
|
.SUFFIXES: .c,.o
|
||||||
|
.PHONY: all clean checkenv $(TARGET_NAME)
|
||||||
|
|
||||||
|
all: checkenv $(TARGET_NAME)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -rf $(OBJS) $(TARGET_NAME)
|
||||||
|
|
||||||
|
checkenv:
|
||||||
|
@mkdir -p $(OUTPUT_DIR)
|
||||||
|
|
||||||
|
$(TARGET_NAME):$(OBJS)
|
||||||
|
@$(CC) -o $(OUTPUT_DIR)/$@ $^ $(LDFLAGS)
|
||||||
|
@chmod +x $(OUTPUT_DIR)/$@
|
||||||
|
|
||||||
|
%.o:%.c
|
||||||
|
@$(CC) -o $@ -c $< $(CFLAGS)
|
||||||
7
03-segfault/segfault.c
Normal file
7
03-segfault/segfault.c
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int *ptr = NULL; // 初始化一个指向NULL的指针
|
||||||
|
*ptr = 1; // 尝试写入NULL指针引用的地址,这将导致段错误
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user