Program loading and Execution (vi)--"x86 assembly language: From the actual mode to the protection mode" Reading notes 26
What can I learn from this article?
- Glossary of conditions for NASM
- When compiling with NASM, define macros with command-line options
- Conditional statements for Makefile
- overriding variable values in makefile on the Make command line
- The 13th chapter exercises the solution
- Review how to construct a stack segment descriptor
We went on to the last post and said.
In my revised document, a conditional compilation is used.
Like what:
%ifdef DEBUG put_core_salt: ;打印内核的符号 ... ... put_usr_salt: ;打印用户的符号 ... ... %endif
This is explained below.
1. Glossary of conditions
Similar to the C preprocessor, NASM allows a compilation of a source code only when a particular condition is satisfied.
Note that the preprocessor directives for the C language are #
some of the commands that begin with the characters, nasm the preprocessor directives of the compiler %
.
1.1 assembly only when a particular condition is met
%if<condition> ;if <condition>满足时接下来的代码被汇编。 ......%elif<condition2> if<condition>不满足,而<condition2>满足时,该段代码被汇编。 ......%else ;当<condition>跟<condition2>都不满足时,该段代码被汇编。 ......%endif
%else
The %elif
clause is optional, and more than one clause can be used %elif
.
1.2 Testing whether a single-line macro exists
%ifdef DEBUG ...%endif
If we define a macro DEBUG
, the code at the ellipsis will be assembled, otherwise it will not.
DEBUG
For example, you can use two methods to define a macro.
1.3 Defining macros directly in your code
%define DEBUG
1.4 through command-line options
When compiling the file, use the -d 宏名称
.
-d DEBUG
For example:
nasm c13_core.asm -o c13_core.bin -d DEBUG
Note: -d
you can write a -D
space between it and the macro name that follows it.
For example:
nasm c13_core.asm -o c13_core.bin -dDEBUG
2. About Makefile
Because the conditional assembly was added, makefile is not the same as in the previous blog post.
Previous post address:
Program loading and Execution (v)--"x86 assembly language: From the actual mode to the protection mode" Reading notes 25
The modified makefile are as follows.
DEBUG =0BIN = C13_mbr.bin c13_core.bin c13.bin emptya_dir =/home/cjy/a.imgc_dir =/home/cjy/c.imgall:$(BIN). Phony:all cleanc13_mbr.bin:c13_mbr.asm NASM$<-O[email protected]Ddif=[email protected]of=$(A_dir) C13_core.bin:c13_core.asmifeq ($(DEBUG),1) NASM$<-O[email protected]-D DEBUGElseNasm$<-O[email protected]endif DDif=[email protected]of=$(C_dir) bs= +seek=1Conv=notruncc13.bin:c13.asm NASM$<-O[email protected]Ddif=[email protected]of=$(C_dir) bs= +seek= -Conv=notruncempty:diskdata.txt DDif=$<of=$(C_dir) bs= +seek= -Conv=notrunc Touch[email protected]Clean$(RM)$(BIN)
2.1 Article Statements
First, we define a variable (also called a macro) DEBUG
and assign it a value of 0;
It is important to note the following lines:
ifeq ($(DEBUG),1) $<[email protected] -DDEBUGelse $<[email protected] endif
The conditional statement for Makefile is used here. When you perform make, different execution branches are selected according to the different conditions of the runtime.
In this example, when DEBUG
the value of the variable is 1 o'clock, it executes nasm $< -o [email protected] -D DEBUG
;
When DEBUG
the value of the variable is not 1 o'clock, it is executed nasm $< -o [email protected]
;
When we want to compile the source file with debug information, we can modify the value in makefile DEBUG
to 1.
But is there a simpler way to do it?
2.2 Defining variables in the command line
When a variable (macro) definition in the command line conflicts with a definition in makefile, the definition in the command line prevails. So, we can add it when we execute make 变量=新值
to overwrite the value of the variable in the makefile file.
For the example in this article, in addition to modifying the value of 1 in Makefile DEBUG
, there is another way to assign a value to a variable (macro) on the command line.
make"DEBUG=1"
Note: When there are no spaces, the quotation marks can also be omitted. Because the macro definition must be passed as a single parameter, avoid using spaces, so it is more appropriate to use quotation marks.
3. The 13th Chapter Exercise solution
In this chapter, the user program gives only the recommended stack size, but does not provide stack space. Now, modify the kernel program and user program, change the user program to provide the stack space itself. Requirement: The stack segment must be defined after the user's program header.
Here, I give my own answers for the reference of the learners.
3.1 For source files
c13.asm
The modification
There are two modifications. The first place is:
Because the stack space is provided by the user program, the assembly address and size of the stack must be specified so that the kernel program has enough information to create a stack segment descriptor for the user.
The second place is:
Since the topic already requires that the stack segment must be defined behind the user's program head, this is followed by a header definition stack space.
Small Episode
Compile this file, will error.
c13.asm:14error: division operator may only be applied to scalar valuesmake*** [c13.bin] 错误 1
Oh, why is that? I changed it.
stack_len dd (stack_end-0)/(4*1024
Still reported the same mistake.
By looking at the information, I found some friends answered:
A label is a relocatable value--its value was modified by the Linker/loader. The difference between and labels (in the same section) are a scalar value, and NASM would work with it.
Well, since the difference between the two labels of the same section is scalar, I'm writing this:
stack_len dd (stack_end-stack_start)/(4*1024)
In fact stack_start
, before this marking is not, I have to do in order to do the difference value specifically added.
You also don't say, so the photo works, no error.
3.2 to the source file
c13_core.asm
The modification
The code on the left (with the book Code), the kernel allocates memory for the user stack, and then computes the high-end physical address of the stack.
The Code on the right (exercise code), the kernel does not need to allocate memory, just remove the stack from the head of the start address, and then calculate the stack of high-end physical address.
This code is I wrote six months ago, but now read it also feel strange. Then explain the most critical 3 lines and deepen your memory.
469 mov edx,edi470 add edx,[edi+0x08] ; 栈段起始的线性地址471 add eax,edx ; 得到栈的高端物理地址
At this point, DS points to the 0-4GB data segment, and the content in EDI is the load address of the user program.
469:edx is the loading address of the user program;
470: Obtained from the user's head offset 0x08 section.stack.start
, plus the user program's load address (EDX), the user stack is the starting address.
471: The base address in the stack descriptor should be the high-end physical address of the stack space, so add the stack size (in EAX).
If you do not understand why you are constructing a stack descriptor, you can refer to my blog post:
How to construct a stack segment descriptor
3.3 Verifying the program in Bochs
Our changes, right? "Practice is a real truth."
3.3.1 Verification Ideas
Because the stack space is provided by the user program, the kernel only creates the corresponding stack segment descriptor based on the header information. So what we want to verify is whether the stack descriptor and the user-defined stack match. In the above mentioned blog post, I have already elaborated how to construct the stack segment descriptor.
The header structure of the user program is as follows:
The user program of this experiment has 3 symbols, so the total head length is, 0x328
because the loading address of the user program is 0x100000
, so the starting address of the stack space is, 0x100328
and because the stack space size is defined as 0x1000(4KB)
, so the high-end physical address of the stack space is 0x100328+0x1000=0x101328
,
This should be the base address of the stack descriptor.
The valid segment bounds should be 0xFFFFFFFF-栈的大小(以字节为单位)
, that 0xFFFFFFFF-0x1000=0xFFFFEFFF
is, this should be the segment bounds in the stack segment descriptor.
3.3.2 Validation Results
Run the program in Bochs, run up, Ctrl
+ C
Pause the program, enter info gdt
the information that can view GTD. We see in:
The description of the Yellow dash matches our reasoning. So, our changes are correct.
"End"
Program loading and Execution (vi)--"x86 assembly language: From the actual mode to the protection mode" Reading notes 26