C语言练习
2023-06-09
- 练习程序。
sb.s_blocks_per_group
块中指定。0D000000
1000
05
01
6673746162
000000
01 28 00 60
转换为二进制为0000 0001 0010 1000 0000 0000 0110 0000
,其中31~19位为0000 0001 0010 1
,将此二进制转为16进制为37。typedef struct {
UINTN Signature;
/// All handles list of IHANDLE
LIST_ENTRY AllHandles;
/// List of PROTOCOL_INTERFACE's for this handle
LIST_ENTRY Protocols;
UINTN LocateRequest;
/// The Handle Database Key value when this handle was last created or modified
UINT64 Key;
} IHANDLE;
typedef
EFI_STATUS
(EFIAPI *EFI_OPEN_PROTOCOL)(
IN EFI_HANDLE Handle, //安装了此Protocol的Handle
IN EFI_GUID *Protocol, //要打开的Protocol的GUID
OUT VOID **Interface OPTIONAL, //返回打开的Protocol
IN EFI_HANDLE AgentHandle, //使用此Protocol的Image(存疑)
IN EFI_HANDLE ControllerHandle, //如果打开的是Protocol是符合UEFI驱动模型的驱动,则此参数为控制Protocol接口的控制器,否则为可选的,可能为NULL
IN UINT32 Attributes //打开Protocol的参数
);
/**
@retval EFI_SUCCESS 成功返回指定的Protocol
@retval EFI_UNSUPPORTED 此Handle没有安装此Protocol
**/
typedef
EFI_STATUS
(EFIAPI *EFI_HANDLE_PROTOCOL)(
IN EFI_HANDLE Handle, //安装了此Protocol的Handle
IN EFI_GUID *Protocol, //此Protocol的GUID
OUT VOID **Interface //返回此Protocol的实例
);
typedef
EFI_STATUS
(EFIAPI *EFI_LOCATE_PROTOCOL)(
IN EFI_GUID *Protocol, //此Protocol的GUID
IN VOID *Registration OPTIONAL, //不知道干啥用的,描述时从RegisterProtocolNotify()获得的key
OUT VOID **Interface //返回此Protocol的实例
);
struct _EFI_DRIVER_BINDING_PROTOCOL {
EFI_DRIVER_BINDING_SUPPORTED Supported; //检查设备控制器是否支持驱动
EFI_DRIVER_BINDING_START Start; //安装驱动并启动设备
EFI_DRIVER_BINDING_STOP Stop; //停止设备并卸载驱动
UINT32 Version; //版本
EFI_HANDLE ImageHandle; //镜像句柄
EFI_HANDLE DriverBindingHandle;
};
typedef
EFI_STATUS
(EFIAPI *EFI_DRIVER_BINDING_SUPPORTED)(
//Protocol实例
IN EFI_DRIVER_BINDING_PROTOCOL *This,
//设备控制器句柄
IN EFI_HANDLE ControllerHandle,
//此参数对设备型驱动无效
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
);
typedef
EFI_STATUS
(EFIAPI *EFI_DRIVER_BINDING_START)(
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
);
typedef
EFI_STATUS
(EFIAPI *EFI_DRIVER_BINDING_STOP)(
IN EFI_DRIVER_BINDING_PROTOCOL *This, //Protocol实例
IN EFI_HANDLE ControllerHandle, //停止此控制器句柄上对应的驱动
IN UINTN NumberOfChildren, //子控制器数量
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL //子控制器数组
);
类型 | 说明 |
---|---|
BASE | 常用于库模块的开发 |
SEC | |
PEI_CORE | |
DXE_CORE | |
DXE_DRIVER | |
DXE_RUNTIME_DRIVER | |
DXE_SAL_DRIVER | |
DXE_SMM_DRIVER | |
UEFI_DRIVER | UEFI启动模块 |
UEFI_APPLICATION | UEFI应用模块 |
[Defines]
。!include
来包含其他文件,用#
来表示注释。[Defines]
中定义了各种变量,必须是dsc文件中的第一个。语法格式如下:[Defines]
PLATFORM_NAME = MdeModule
PLATFORM_GUID = 587CE499-6CBE-43cd-94E2-186218569478
PLATFORM_VERSION = 0.98
DSC_SPECIFICATION = 0x00010005
#可选
OUTPUT_DIRECTORY = Build/MdeModule
SUPPORTED_ARCHITECTURES = IA32|X64|EBC|ARM|AARCH64|RISCV64|LOONGARCH64
BUILD_TARGETS = DEBUG|RELEASE|NOOPT
SKUID_IDENTIFIER = DEFAULT
[BuildOptions]
中给出编译器和相关的编译参数。
[LibraryClasses]
用来提供模块所使用的库入口,格式如下:
[LibraryClasses]
PeiCoreEntryPoint|MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf
PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
[Components]
用来定义模块编译,指定模块的INF文件所在的位置。格式如下:[Components]
MdeModulePkg/Application/HelloWorld/HelloWorld.inf
MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf
#这种格式下,{}内的内容只对当前的INF文件有效
AppPkg/Applications/LibSample/MyLibApp/MyLibApp.inf{
<LibraryClasses>
MyLibraryLib|AppPkg/Applications/LibSample/MyLibrary/MyLibrary.inf
}
inf文件是模块的工程文件,描述了模块的属性,如模块由哪些代码组成、依赖了哪些库等。
EDK2的模块一般位于包的子目录下,如果是提供库的模块一般位于Library子目录下,如果是UEFI Application,一般位于Application下。
INF文件包含很多节标志,包括[Defines]
、[Sources]
等。
[Defines]
中定义了各种变量,后续编译步骤中需要使用这些变量。
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = Uefi_Main
FILE_GUID = 6937936E-ED34-44ab-AE97-1FA5E7ED2116
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
ENTRY_POINT = UefiMain
[Sources]
用于列出模块中所有的源文件和资源文件,这些文件位于inf所在的目录或者子目录中。[Sources]
Uefi_Main.c
[BuildOptions]
和dsc文件的[BuildOptions]
语法格式基本相同,INF文件只对本模块有效,DSC对包下所有模块有效。[Protocols]
列出了模块时用到的协议,在INF文件中列出的是协议的GUID。[Protocols]
gEfiSimpleTextInputExProtocolGuid
gEfiGraphicsOutputProtocolGuid
LibraryClasses
列出本模块需要链接的库。模块如果需要添加库,一般需要:
[LibraryClasses]
中添加库名[LibraryClasses]
中寻找这个库,如果没有,则需要添加编译此库的INF文件。[LibraryClasses]
UefiLib
ShellCEntryLib
[Packages]
列出本模块引用的所有包的DEC文件。[Packages]
MdePkg/MdePkg.dec
ShellPkg/ShellPkg.dec
<Uefi.h>
定义了UEFI中的基本数据类型和核心数据结构。
<Library/UefiLib.h>
提供通用的库函数。
<Library/BaseLib.h>
提供字符串处理、数学、文件路径处理等相关库函数。
<Library/BaseMemoryLib.h>
处理内存的库函数。
<Library/DebugLib.h>
功能调试输出的库函数。
ImageHandle指向了模块自身加载到内存的Image对象。SystemTable是UEFI应用和UEFI内核交互的桥梁,通过它可以获得UEFI提供的各种服务,包括BS服务和CS服务。
在EFI_SYSTEM_TABLE的结构体中,提供了访问BS服务和RT服务的指针。针对一些常用的Protocol的接口,如ConsoleIn(键盘)和ConsoleOut(屏幕)也提供了访问指针。
[Defines] [FD] [FV] [Capsule] [VTF] [Rule] [OptionRom]
等几个节组成。#预处理
gcc -E -o hello.i hello.c
#编译(包含预处理)
gcc -S -o hello.s hello.i
#汇编(包含预处理和编译)
gcc -c -o hello.o hello.s
#链接(包含上面的步骤)
gcc -o hello hello.o
参数 | 描述 |
---|---|
-E | 预处理 |
-c | 把预处理、编译、汇编都做的,但是不链接 |
-o | 指定输出文件 |
-I | 指定头文件目录 |
-L | 指定链接时使用库文件的目录 |
-l(小L) | 指定链接哪一个库文件,如-labc就是链接libabc.so |
-v | 显示编译器驱动程序、预处理器、编译器办吧等信息。 |
-Wall | 打开所有需要注意的警告信息 |
#include <xxx> //在标准库的目录开始搜索(包括使用-Idir定义的目录)
#include "xxx" //先从用户的工作目录开始搜索,再搜索标准库目录
#创建动态链接库
gcc -shared -o libsub.so sub.o sub1.o
#使用当前目录下得sub库
gcc -o test main.o -lsub -L ./
#运行时需要指定动态库的位置,可以将libsub.so移动到/lib目录下,或者配置一个环境变量
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/xiaox
#生成静态库
ar crs libsub.a sub.o sub2.o
#将静态库打包到程序里
gcc -o tet main.o libsub.a
#列出头文件目录、库目录(LIBRARY_PATH)等
echo 'main(){}'| gcc -E -v -
target : prerequires1 prerequires2 ...
command1
command2
...
A := XXX //立即变量
B = XXX //延时变量,在使用时才生效
C += yyy //拼接字符串
D ?= xxx //如果D之前定义过,则此语句无效;如果之前定义值,此语句定义。
A := $(C)
B = $(C)
C = abc
D ?= weidongshan
all:
@echo A = $(A)
@echo B = $(B)
@echo D = $(D)
C += 123
#结果
#A = 立即变量定义式就确定,所以A的值为空
#B = abc 123 延时变量只有在用到时才确定,当执行make时,会解析Makefile里面的所有变量。
#D = weidongshan 因为D在前面没有定义,所以是此值。
*.c
表示所有的.c结尾的文件。$@
表示target。$<
表示第一个依赖文件。$^
表示所有的依赖文件。clean :
rm -rf *.o
.PHONY : clean
#对于list中的每一个var,执行text的动作
$(foreach var,list,text)
#例
A := a b c
B := $(foreach f, $(A), $(f).c)
all :
@echo B = $(B)
$(filter pattern...,text) # 在text中取出符合patten格式的值
$(filter-out pattern...,text) # 在text中取出不符合patten格式的值
#例
A := a b c dxx
B := $(filter %xx, $(A))
all :
@echo $(B)
#结果为dxx
#如果var中的值匹配pattern,就将它替换为replacement
$(patsubst pattern, replacement, $(var))
#例
files := a.c b.c c.c d.c e.c abc
dep_files := $(patsubst %.c,%.d,$(files))
all :
@echo dep_files = $(dep_files)
#结果为 dep_files = a.d b.d c.d d.d e.d abc
#-M获取c.c依赖的头文件
#-MF将依赖输出的c.d的文件
gcc -M -MF c.d c.c
objs = a.o b.o c.o
dep_files := $(patsubst %,.%.d, $(objs))
dep_files := $(wildcard $(dep_files))
test : $(objs)
gcc -o test $^
%.o : %.c
gcc -c -o $@ $< -M -MF .$@.d
ifneq ($(dep_files),)
include $(dep_files)
endif
clean:
rm *.o test
rm $(dep_files)
.PHONY: clean