C++ C在cygwin上编译到目标独立平台

C++ C在cygwin上编译到目标独立平台,c++,c,operating-system,cygwin,C++,C,Operating System,Cygwin,我有下面的代码,我想静态编译以在一个小操作系统上运行(几乎没有操作系统!我会在激活保护模式后将机器代码加载到内存中的特定地址)。到目前为止,我的尝试都没有成功。首先可能吗?如果不是,那么最简单的方法是什么 #include <stdio.h> #define TXT_COLOR 7 #define printf(...) {sprintf(str,__VA_ARGS__);\ int i=0; while(str[i])\

我有下面的代码,我想静态编译以在一个小操作系统上运行(几乎没有操作系统!我会在激活保护模式后将机器代码加载到内存中的特定地址)。到目前为止,我的尝试都没有成功。首先可能吗?如果不是,那么最简单的方法是什么

#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;
}
#包括
#定义TXT_颜色7
#定义printf(…){sprintf(str,u-VA_-ARGS_uu)\
int i=0;while(str[i])\
写入字符串(TXT_COLOR,&str[i++]);}
//sprintf接受printf参数和格式数据
//然后写入字符串将数据输出到视频缓冲区
int write_字符串(int color,const char*string);
int_start()
{
字符str[256]=“”;
char c='Z';
int j=9;
浮点数f=9.76777;
printf(“%d\t%f\t%c\这是一个测试\n测试更多!\n\n”,j,f,c);
}
int write_字符串(int color,const char*string)
{/*函数将字符写入视频缓冲区*/
volatile char*videoBuff=(volatile char*)0xB8000;
而(*字符串!=0)
{
*videoBuff++=*字符串++;
*videoBuff++=彩色;
}
返回0;
}

对于这个答案,我假设tiny OS是一个非常简单的内核,可以引导到32位保护模式,其他功能不多

没有C标准库:-( 首先,您的程序有一个问题,您使用的是C标准库中的
sprintf
。恐怕您必须编写自己的
sprintf
(相对容易),或者将一些*libc实现移植到您的操作系统中(稍具挑战性)。我建议您在第一次测试中,只需调用原始的
write_string
函数。让我们在
\u start
的末尾放置一个无限循环——请记住,“从main返回”涉及很多尚未在裸机操作系统上实现的幕后事件:

#定义TXT_颜色7
int write_字符串(int color,const char*string);
int_start(){
写字符串(TXT颜色,“这是一个测试”);
对于(;);
}
/*函数将字符写入视频缓冲区*/
int write_字符串(int color,const char*string){
volatile char*videoBuff=(volatile char*)0xB8000;
而(*字符串!=0){
*videoBuff++=*字符串++;
*videoBuff++=彩色;
}
返回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)。我们还需要指定哪个函数将作为入口点,即
\u start
(默认情况下,GCC会在函数名前加一个下划线,因此它的真实名称实际上是
\u start
):

ld-mi386pe-Ttext 0x200000--entry\uu start-o prog.pe prog.o
最后,我们将PE二进制文件
prog.PE
转换为原始的平面二进制文件(
prog.bin
),无需任何操作系统提供的基础设施即可运行。这是您将加载到内存中并直接执行的文件:

objcopy-O二进制prog.pe prog.bin
健康检查 要在尝试从操作系统加载输出之前检查输出是否正常,请查看反汇编:

objdump-d prog.pe
您应该在最顶端看到
\u start
功能,以及您指定的加载地址。例如:

节的反汇编。文本:
00200000 :
200000:55%推压ebp
200001:89 e5 mov%esp,%ebp
200003:83 ec 18子$0x18,%esp
...
然后确保
prog.bin
反汇编的原始字节与上述字节匹配(符号/名称将不可见,因为它们都已被剥离)。例如:

$objdump-D-b binary-m i386 prog.bin
分解截面。数据:
00000000 :
0:55推力%ebp
1:89 e5 mov%esp,%ebp
3:83 ec 18子$0x18,%esp
...

Peternd,非常感谢您详细而有用的回答。不过,我想我可能可以链接到libc。一个带-static选项,但当我分解libc时。a _sprintf只有3行代码,2行是nop指令!我希望由于sprint f函数不依赖操作系统,我可以使用它格式化数据,然后使用自定义低级代码在屏幕上进行编写。再次感谢您的输入。Cygwin的libc.a仅包含存根。sprintf的实际实现在cygwin1.dll中,您无法静态链接到该文件。您最好实现自己的版本或在中或其他位置进行静态编译。现在一切都有意义了。感谢您的澄清激动。