MinGW的ld无法在非PE输出文件上执行PE操作 [英] MinGW's ld cannot perform PE operations on non PE output file

查看:64
本文介绍了MinGW的ld无法在非PE输出文件上执行PE操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道还有其他类似的问题,无论是否为StackOverflow.我为此做了很多研究,但仍然没有找到一个解决方案.我正在做一个作为副项目的操作系统.我已经在Assembly中完成了所有工作,但是现在我想加入C代码.为了进行测试,我制作了以下汇编代码文件(称为test.asm):

I know there are some other similar questions about this out there, be it StackOverflow or not. I've researched a lot for this, and still didn't find a single solution. I'm doing an operative system as a side project. I've been doing all in Assembly, but now I wanna join C code. To test, I made this assembly code file (called test.asm):

[BITS 32]

GLOBAL _a

SECTION .text

_a:
    jmp $

然后我制作了这个C文件(称为main.c):

Then I made this C file (called main.c):

extern void a(void);
int main(void)
{
    a();
}

要链接,我使用了这个文件(称为make.bat):

To link, I used this file (called make.bat):

"C:\minGW\bin\gcc.exe"  -ffreestanding -c -o c.o main.c
nasm -f coff -o asm.o test.asm
"C:\minGW\bin\ld.exe" -Ttext 0x100000 --oformat binary -o out.bin c.o asm.o

pause

我已经研究了很长时间,但我仍在努力寻找答案.我希望这不会被标记为重复.我承认存在类似的问题,但是所有问题都有不同的答案,没有一个对我有用.

I've been researching for ages, and I'm still struggling to find an answer. I hope this won't be flagged as duplicate. I acknowledge about the existence of similar questions, but all have different answers, and none work for me.

问题:我在做什么错了?

推荐答案

旧的MinGW版本存在"ld"根本无法创建非PE文件的问题.

Old MinGW versions had the problem that "ld" was not able to create non-PE files at all.

也许当前版本有相同的问题.

Maybe current versions have the same problem.

解决方法是使用"ld"创建PE文件,然后使用"objcopy"将PE文件转换为二进制,HEX或S19.

The work-around was creating a PE file with "ld" and then to transform the PE file to binary, HEX or S19 using "objcopy".

-编辑--

再次考虑这个问题,我看到了两个问题:

Thinking about the question again I see two problems:

正如我已经说过的,某些版本的"ld"在创建二进制"输出(而不是"PE","ELF"或使用的任何格式)时遇到问题.

As I already said some versions of "ld" have problems creating "binary" output (instead of "PE", "ELF" or whatever format is used).

代替:

ld.exe --oformat binary -o file.bin c.o asm.o

您应按照以下顺序创建二进制文件:

You should use the following sequence to create the binary file:

ld.exe -o file.tmp c.o asm.o
objcopy -O binary file.tmp file.bin

这将创建一个名为"binary.tmp"的".exe"文件;然后"objcopy"将根据".exe"文件创建原始数据.

This will create an ".exe" file named "binary.tmp"; then "objcopy" will create the raw data from the ".exe" file.

第二个问题是链接本身:

The second problem is the linking itself:

"ld"采用类似于".exe"的文件格式-即使输出文件是二进制文件.这意味着...

"ld" assumes a ".exe"-like file format - even if the output file is a binary file. This means that ...

  • ...您甚至无法确定目标代码"main.o"是否确实位于结果目标代码的首地址."ld"也将被允许将"a()"的代码置于"main()"之前,甚至将内部"代码置于"a()"和"main()"之前.
  • ...寻址方式略有不同,这意味着如果您做错了什么,将会创建很多填充字节(也许在文件的开头!).

我看到的唯一可能性是创建一个链接程序脚本"(有时称为链接器命令文件"),并在汇编代码中创建一个特殊的部分(因为我通常使用的另一个汇编程序不是"nasm",我不知道)如果此处的语法正确):

The only possibility I see is to create a "linker script" (sometimes called "linker command file") and to create a special section in the assembler code (because I normally use another assembler than "nasm" I do not know if the syntax here is correct):

[BITS 32]
GLOBAL _a
SECTION .entry
    jmp _main
SECTION .text
_a:
    jmp $

在链接程序脚本中,您可以指定哪些部分以什么顺序出现.指定".entry"是文件的第一部分,因此可以确保它是文件的第一条指令.

In the linker script you can specify which sections appear in which order. Specify that ".entry" is the first section of the file so you can be sure it is the first instruction of the file.

在链接描述文件中,您也可以说多个部分(例如".entry",.text"和".data")应合并为一个部分.这很有用,因为在PE文件中节通常是0x1000字节对齐的!如果您不将多个部分合并为一个,则在这些部分之间会得到很多存根字节!

In the linker script you may also say that multiple sections (e.g. ".entry", ".text" and ".data") should be combined into a single section. This is useful because sections are normally 0x1000-byte-aligned in PE files! If you do not combine multiple sections into one you'll get a lot of stub bytes between the sections!

不幸的是,我不是链接描述文件的专家,所以我不能为您提供太多帮助.

Unfortunately I'm not the expert for linker scripts so I cannot help you too much with that.

使用"-Ttext"也是有问题的:

Using "-Ttext" is also problematic:

在PE文件中,部分的实际地址计算为图像基础" +相对地址"."-Ttext"参数将仅影响相对地址".因为第一部分的相对地址"通常在Windows中固定为0x1000,所以"-Ttext 0x2000"除了在第一部分的开头填充0x1000存根字节外,什么也不会做.但是,您根本不会影响".text"的起始地址-您仅在".text"部分的开头填充存根字节,以便第一个有用字节位于0x2000处.(也许某些"ld"版本的行为有所不同.)

In PE files the actual address of a section is calculated as "image base" + "relative address". The "-Ttext" argument will influence the "relative address" only. Because the "relative address" of the first section is typically fixed to 0x1000 in Windows a "-Ttext 0x2000" would do nothing but filling 0x1000 stub bytes at the start of the first section. However you do not influence the start address of ".text" at all - you only fill stub bytes at the start of the ".text" section so that the first useful byte is located at 0x2000. (Maybe some "ld" versions behave differently.)

如果您希望文件的第一部分位于地址0x100000,则应在链接描述文件中使用等价的"-Ttext 0x1000"(如果使用了链接描述文件,则不使用-Ttext)并定义图片库"到0xFF000:

If you wish that the first section of your file is located at address 0x100000 you should use the equivalent of "-Ttext 0x1000" in the linker script (-Ttext is not used if a linker script is used) and define the "image base" to 0xFF000:

ld.exe -T linkerScript.ld --image-base 0xFF000 -o binary.tmp a.o main.o

.text"部分的内存地址将为0xFF000 + 0x1000 = 0x100000.

The memory address of the ".text" section will be 0xFF000 + 0x1000 = 0x100000.

("objcopy"生成的二进制文件的第一个字节将是第一节的第一个字节-表示内存地址0x100000.)

(And the first byte of the binary file generated by "objcopy" will be the first byte of the first section - representing memory address 0x100000.)

这篇关于MinGW的ld无法在非PE输出文件上执行PE操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆