What can I learn from this article?
We went on to the last post and said.
In my revised document, a conditional compilation is used.
%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
%if<condition> ;if <condition>满足时接下来的代码被汇编。 ......%elif<condition2> if<condition>不满足，而<condition2>满足时，该段代码被汇编。 ......%else ;当<condition>跟<condition2>都不满足时，该段代码被汇编。 ......%endif
1.2 Testing whether a single-line macro exists
%elif clause is optional, and more than one clause can be used
%ifdef DEBUG ...%endif
If we define a macro
DEBUG , the code at the ellipsis will be assembled, otherwise it will not.
1.3 Defining macros directly in your code
DEBUGFor example, you can use two methods to define a macro.
1.4 through command-line options
When compiling the file, use the
-d 宏名称 .
nasm c13_core.asm -o c13_core.bin -d DEBUG
-d you can write a
-D space between it and the macro name that follows it.
2. About Makefile
nasm c13_core.asm -o c13_core.bin -dDEBUG
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.
2.1 Article Statements
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)
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 ;
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.
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
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.
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)
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.
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
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
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.
Run the program in Bochs, run up,
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.
Program loading and Execution (vi)--"x86 assembly language: From the actual mode to the protection mode" Reading notes 26