Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 程序集代码与代码的gdb显示不同_C_Assembly_Gdb_Kernel_Bootloader - Fatal编程技术网

C 程序集代码与代码的gdb显示不同

C 程序集代码与代码的gdb显示不同,c,assembly,gdb,kernel,bootloader,C,Assembly,Gdb,Kernel,Bootloader,我从《从0到1的操作系统》一书中学习了操作系统,我试图在我的内核main中显示代码,但是在GDB中显示的代码并不相同,尽管我跳到了作为入口点的地址 bootloader.asm ;************************************************* ; bootloader.asm ; A Simple Bootloader ;************************************************* bits 16 start: jmp

我从《从0到1的操作系统》一书中学习了操作系统,我试图在我的内核main中显示代码,但是在GDB中显示的代码并不相同,尽管我跳到了作为入口点的地址

bootloader.asm

;*************************************************
; bootloader.asm 
; A Simple Bootloader
;*************************************************
bits 16
start: jmp  boot

;; constants and variable definitions
msg db "Welcome to My Operating System!", 0ah, 0dh, 0h

boot:

    cli ; no interrupts 
    cld ; all that we need to init
    
    mov ax, 0x0000

    ;; set buffer
    mov es, ax  
    mov bx, 0x0600

    mov al, 1   ; read one sector
    mov ch, 0   ; track 0
    mov cl, 2       ; sector to read
    mov dh, 0   ; head number
    mov dl, 0   ; drive number
        
    mov ah, 0x02    ; read sectors from disk    
    int 0x13      ; call the BIOS routine
    jmp 0x0000:0x0600   ; jump and execute the sector!
    
    hlt ; halt the system 

; We have to be 512 bytes. Clear the rest of the bytes with 0

times 510 - ($-$$) db 0
dw 0xAA55 ; Boot Signature
readelf-l主

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x600
  Start of program headers:          52 (bytes into file)
  Start of section headers:          12888 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         3
  Size of section headers:           40 (bytes)
  Number of section headers:         12
  Section header string table index: 11

Elf file type is EXEC (Executable file)
Entry point 0x600
There are 3 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000000 0x00000000 0x00000000 0x00094 0x00094 R   0x4
  LOAD           0x000000 0x00000000 0x00000000 0x00094 0x00094 R   0x4
  LOAD           0x000100 0x00000600 0x00000600 0x00006 0x00006 R E 0x100

 Section to Segment mapping:
  Segment Sections...
   00     
   01     
   02     .text 
readelf-l主

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x600
  Start of program headers:          52 (bytes into file)
  Start of section headers:          12888 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         3
  Size of section headers:           40 (bytes)
  Number of section headers:         12
  Section header string table index: 11

Elf file type is EXEC (Executable file)
Entry point 0x600
There are 3 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000000 0x00000000 0x00000000 0x00094 0x00094 R   0x4
  LOAD           0x000000 0x00000000 0x00000000 0x00094 0x00094 R   0x4
  LOAD           0x000100 0x00000600 0x00000600 0x00006 0x00006 R E 0x100

 Section to Segment mapping:
  Segment Sections...
   00     
   01     
   02     .text 
main.c

void main(){}
objdump-z-M intel-S-D build/os/main

Disassembly of section .text:

00000600 <main>:
void main(){}
 600:   55                      push   ebp
 601:   89 e5                   mov    ebp,esp
 603:   90                      nop
 604:   5d                      pop    ebp
 605:   c3                      ret    
显示主代码的gdb代码

set architecture i8086
target remote localhost:26000
b *0x7c00
set disassembly-flavor intel
layout asm
layout reg
symbol-file build/os/main
b main

jg/dec esp/inc esi
是ELF幻数,而不是机器码!从
ndissm-b32/bin/ls
的输出开始,您将看到相同的内容。(
ndisam
始终将其输入视为一个简单的二进制文件;它不查找任何元数据。)

7F 45 4C 46是0x7F字节后的字符串
“ELF”
,是将文件格式标识为ELF的ELF幻数。在
main
的实际机器代码之前,后跟更多的ELF头字节
objdump-D
反汇编所有ELF节,但它仍然解析ELF头,而不像
ndisam
那样反汇编它们。因此,您最终还是看到了
.text
部分的代码,因为其他部分都是空的(因为您链接了这个可执行文件,没有libc或CRT startfiles,并且以C main作为ELF入口点?!?)

您正在跳转到ELF文件的开头,就像它是一个平面二进制文件一样。事实并非如此,编写ELF程序加载器并不是那么简单。ELF程序头(可以解析的
readelf
文件头)告诉您哪个文件偏移量位于哪个地址。
.text
部分的开头将在文件中的某个偏移处,由于明显的原因,不会与ELF幻数重叠。(尽管如果您能找到合适的方法,它可能与ELF标题重叠:)

然后,一旦按照程序头中的指定将文件映射到内存中,就跳转到ELF入口点地址(本例中为0x600)。(这通常不是一个函数;在像Linux这样的真实操作系统中,你不能从入口点
ret
。相反,你需要进行退出系统调用。)你也不能在这里,因为你可以
jmp
调用它,而不是
call

这就是为什么
\u start
main
分开的原因;使用编译器生成的
main
作为其入口点构建程序是不可行的

当然,这项工作的大部分都是注定的,因为您要在CPU仍处于16位实模式的情况下跳转到main。但您的main是针对32位模式编译/组装的。您可以使用
gcc-m16
来解决这一问题,以便为16位模式组装gcc输出,必要时使用操作数大小+地址大小前缀

不执行任何操作的主设备的机器代码实际上将在16位和32位模式下工作。如果未经优化就使用
返回0
,情况就不会是这样:mov eax、imm32的操作码(不带前缀)意味着不同的指令长度,这取决于CPU在何种模式下解码,因此在16位模式下解码将写入AX,并留下2字节的零


最容易做的事情可能是将“内核”转换为平面二进制文件,而不是在引导加载程序中编写ELF程序加载程序。遵循osdev教程,因为很多东西都可能出错,例如,您必须注意静态数据

或者参见一个在切换到32位保护模式后调用C函数的引导加载程序示例


请参阅中的更多链接。

您使用了哪些命令将源代码构建到可执行文件中,以及您是如何在任何东西上运行GDB的?在QEMU遥控器中?你有没有可能用ASCII文本覆盖代码?检查“代码”的hextump,查看数据是否与其他内容类似。(虽然这不太可能,但对于
addr/m32,r32
01
)是的,我在qemu环境中运行了它。我通过本地主机将程序与gdb连接。我不知道你用ASCII文本覆盖代码是什么意思。你的命令(特别是
gcc-m16
)与你的
objdump
输出不匹配
-m16
将使用
66 55 push ebp
等等:16位模式下的32位操作数大小,使用66前缀。(objdump将其反汇编为
push bp
,因为它位于32位ELF可执行文件中)。喜欢上了。您的objdump输出看起来像是使用
-m32
编译的。这并不是说它改变了答案,除了关于需要
-m16
的部分,但它意味着你的问题不是自相矛盾的。