【问题标题】:C function doesn't return after using __asm__ command使用 __asm__ 命令后 C 函数不返回
【发布时间】:2021-07-16 00:46:23
【问题描述】:

我正在尝试使用指南从头开始构建操作系统,https://github.com/cfenollosa/os-tutorial。 到目前为止,我已经调试了我所做的项目(第 16 章),当我尝试运行它时遇到了一个问题,我发现调用 void port_byte_out(unsigned short port, unsigned char data) 后 ip 没有变回父函数。

  • ports.h - 被调用函数的头文件
unsigned char port_byte_in(unsigned short port);
void port_byte_out(unsigned short port, unsigned char data);
unsigned short port_word_in(unsigned short port);
void port_word_out(unsigned short port, unsigned short data);
  • ports.c - 被调用函数的代码文件
    unsigned char result;
    __asm__ ( " in %%dx , %%al " : "=a" ( result ) : "d" ( port ));
    return result ;
}

void port_byte_out ( unsigned short port , unsigned char data ) {
    __asm__ ( "out %%al , %%dx " : : "a" ( data ) , "d" ( port ));
}

unsigned short port_word_in ( unsigned short port ) {
    unsigned short result ;
    __asm__ ( " in %%dx , %%ax " : "=a" ( result ) : "d" ( port ));
    return result;
}

void port_word_out ( unsigned short port , unsigned short data ) {
    __asm__ ( " out %%ax , %%dx " : : "a" ( data ) , "d" ( port ));
}
  • screen.c: set_cursor_offset(int) - 调用函数的代码
void set_cursor_offset(int offset) {
    offset /= 2;
    port_byte_out(REG_SCREEN_CTRL, 14);
    port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset >> 8));
    port_byte_out(REG_SCREEN_CTRL, 15);
    port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset & 0xff));
}
  • makefile - 可能是非常规使用的东西.. 抱歉,我是新手 :)
# $@ = target file
# $< = first dependcy
# $^ = all dependecies

C_SOURCES = $(wildcard kernel/*.c drivers/*.c)
HEADERS = $(wildcard kernel/*.h drivers/*.h)
OBJ = ${C_SOURCES:.c=.o}

CC = /usr/local/cross/bin/i686-elf-gcc
LD = /usr/local/cross/bin/i686-elf-ld
GDB = gdb

CFLAGS = -g

image.bin: boot_sector.bin kernel.bin
    cat $^ > $@

kernel.bin: boot/kernel_entry.o ${OBJ}
    ${LD} -o $@ -Ttext 0x1000 $^ --oformat binary

kernel.elf: boot/kernel_entry.o ${OBJ}
    ${LD} -g -o $@ -Ttext 0x1000 $^

run: image.bin 
    qemu-system-x86_64 -fda $<

debug: image.bin kernel.elf
    qemu-system-x86_64 -s -fda image.bin &
    ${GDB} -ex "target remote localhost:1234" -ex "symbol-file kernel.elf"

%.o: */%.c ${HEADERS}
    ${CC} ${FLAGS} -ffreestanding -c $< -o $@

%.o: %.asm
    nasm $< -f elf -o $@

%.bin: */%.asm
    nasm $< -f bin -o $@

clean:
    rm -rf *.bin *.dis *.o *.elf
    rm kernel/*.bin kernel/*.o boot/*.bin boot/*.o
    rm drivers/*.bin drivers/*.o
    rm image.bin
  • 文件树-
.
├── bin
├── boot
│   ├── 32bit-gdt.asm     --> gdt table
│   ├── boot_sector.asm   --> boot sector
│   ├── disk_load.asm     --> read from disk function
│   ├── kernel_entry.asm  --> enter kernel - defines kernel_main
│   ├── print_32pm.asm    --> protected mode print(used before using the kernel functions)
│   ├── print.asm         --> real mode print
│   ├── print_hex.asm     --> real mode print hex nums
│   └── switch_32pm.asm   --> asm for switching to protected mode
├── drivers
│   ├── ports.c           --> talking to ports through the functions here
│   ├── ports.h           --> ports.c header file
│   ├── screen.c          --> screen memory writing, cursor and print functions
│   └── screen.h          --> screen.c header file
├── kernel
│   └── kernel_main.c     --> the kernel main
└── Makefile

4 directories, 14 files

【问题讨论】:

  • 乍一看还不错。你怎么知道ip没有变回来?函数是否内联?使用调试器。
  • “当我尝试运行它时” - 你是如何运行它的?您不只是在 ubuntu 下将此代码作为可执行文件运行,对吗?
  • 我使用 qemu 和 gdb 调试器按照说明进行操作,每次我到达 port_byte_out 时,ip 在完成后不会改变,并继续写入地址中的下一个函数 - port_word_in,并继续直到它“重新启动".. 按照说明操作,直到到达 0x7c00 并重新读取引导扇区
  • 你能展示port_byte_out的反汇编,最好是机器码吗?既然你提到7c00,这是引导扇区吗?您因此处于实模式吗?你编译了 16 位的代码吗?
  • 为 64 i868-elf-gcc 编译。 0x7c00 作为我的引导扇区起点。我对这些东西很陌生..我处于保护模式,screen.c 是来自内核代码的文件

标签: c ubuntu gcc kernel inline-assembly


【解决方案1】:

我设法找到了一个解决方案,即使它不遵循传统的编码方式 - 它也有效.. 我只是按原样使用了 asm 函数中的代码 手动内联它们 为什么在我不知道也没有线索之前它不起作用,如果有人有任何可能的想法,我想理解一个合理的解释。 感谢任何试图提供帮助的人!

【讨论】:

  • 这不是答案,而是评论。如果您不回答问题,请留下评论。
猜你喜欢
  • 2019-10-20
  • 1970-01-01
  • 2019-07-06
  • 1970-01-01
  • 1970-01-01
  • 2012-10-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多