我有下面的这段代码,我想对其进行静态编译以在微型OS上运行(几乎没有OS!激活保护模式后,我会将机器代码加载到内存中的特定地址)。到目前为止,我的尝试均未成功。首先有可能吗?如果没有,那么完成这样的事情的最简单方法是什么?
#include <stdio.h>
#define TXT_COLOR 7
#define printf(...) {sprintf(str,__VA_ARGS__);\
int i=0; while(str[i])\
write_string(TXT_COLOR, &str[i++] );}
// sprintf takes printf arguments and format data
// then write_string outputs data to the video buffer
int write_string( int colour, const char *string );
int _start()
{
char str[256]="";
char c='Z';
int j=9;
float f=9.76777;
printf("%d\t%f\t%c\this is a test\n test more!\n\n",j,f,c);
}
int write_string( int colour, const char *string )
{ /* Function to write a character to the video buffer*/
volatile char *videoBuff = (volatile char*)0xB8000;
while( *string != 0 )
{
*videoBuff++ = *string++;
*videoBuff++ = colour;
}
return 0;
}
最佳答案
对于这个答案,我假设微型操作系统是一个非常简单的内核,可以引导至32位保护模式,并且不会做其他事情。
没有C标准库:-(
首先,您的程序存在问题,因为您正在使用C标准库中的sprintf
。恐怕您将不得不编写自己的sprintf
(相对容易)或将* libc的某些实现移植到您的OS中(难度稍大)。我建议您进行第一次测试,只需调用原始的write_string
函数。让我们在_start
的末尾添加一个无限循环-请记住,“从主目录返回”涉及很多幕后发生的事情,这些事情尚无法在裸机OS上实现:
#define TXT_COLOR 7
int write_string( int colour, const char *string );
int _start() {
write_string(TXT_COLOR, "this is a test");
for (;;);
}
/* Function to write a character to the video buffer*/
int write_string( int colour, const char *string ) {
volatile char *videoBuff = (volatile char*)0xB8000;
while( *string != 0 ) {
*videoBuff++ = *string++;
*videoBuff++ = colour;
}
return 0;
}
汇编
使用Cygwin GCC,我们可以分三个阶段将此源文件(我称为
prog.c
)编译为原始二进制文件。首先,我们通过C编译器运行它以生成一个中间目标文件(
prog.o
),确保将其指定为用于32位计算机:cc -m32 -c -o prog.o prog.c
接下来,我们将
prog.o
提供给链接器,并指定32位PE输出格式(在Linux上为32位ELF),并将其加载到内存中的地址(在本示例中为2MB)。我们还需要指定哪个函数将作为入口点,即_start
(默认情况下,GCC在函数名称前加了下划线,因此其真实名称实际上是__start
):ld -mi386pe -Ttext 0x200000 --entry __start -o prog.pe prog.o
最后,我们将PE二进制文件
prog.pe
转换为不需要任何操作系统提供的基础架构即可运行的原始平面二进制文件(prog.bin
)。这是您将加载到内存中并直接执行的内容:objcopy -O binary prog.pe prog.bin
完整性检查
要在尝试从操作系统加载输出之前对其进行完整性检查,请查看反汇编:
objdump -d prog.pe
您应该在最顶部看到
_start
函数,其中包含您指定的加载地址。例如:Disassembly of section .text:
00200000 <__start>:
200000: 55 push %ebp
200001: 89 e5 mov %esp,%ebp
200003: 83 ec 18 sub $0x18,%esp
...
然后确保反汇编
prog.bin
的原始字节与上面的字节匹配(符号/名称将被删除,因此将不可见)。例如:$ objdump -D -b binary -m i386 prog.bin
Disassembly of section .data:
00000000 <.data>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 18 sub $0x18,%esp
...
关于c++ - cygwin上的C编译以目标独立平台为目标,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29859578/