Assembly 为什么';不能为隐式规则定义LD变量吗?
我目前正在学习组装。我编写了简单的测试程序,因此我编写了一个简单的makefile:Assembly 为什么';不能为隐式规则定义LD变量吗?,assembly,makefile,gnu-make,Assembly,Makefile,Gnu Make,我目前正在学习组装。我编写了简单的测试程序,因此我编写了一个简单的makefile: AS = nasm CC = ld
AS = nasm
CC = ld
ASFLAGS = -f elf64
all: hello_name put_digit
hello_name: hello_name.o
put_digit: put_digit.o
clean:
${RM} *.o
fclean: clean
${RM} hello_name put_digit
.PHONY: all clean fclean
我一直认为,隐式规则并不是真正有用的,因为您最终会在任何实质性项目中重写这些规则。但是,尝试在实验时快速建立一个makefile似乎是一个很好的用例,而不是编写一个构建脚本。所以我在这里使用它们
发现没有LD变量是多么令人沮丧,因此我必须破解CC
以获得LD
。
隐式规则也不考虑.asm
文件,因此我必须将它们伪装成.s
文件,尽管我使用的是英特尔/nasm
语法
这有什么好的/历史的原因吗,或者隐式规则是不成熟的吗?有一个内置的和定义的LD
变量,只是它没有在隐式规则中使用。规则本身是:
%: %.o
# recipe to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
将LINK.o
定义为
# default
LINK.o = $(CC) $(LDFLAGS) $(TARGET_ARCH)
我相信这是一条正确的道路。通常,应该调用编译器驱动程序来运行链接器(除非使用自定义链接脚本),它还包括一些编译器提供的启动文件,否则需要自己指定,这是特定于编译器的
考虑这个简单的例子:
$ cat hello.c
int main(int argc, char *argv[]) {
return 0;
}
有人可能认为这是一个完整的程序,但事实并非如此。编译它的平台需要一些额外的准备工作。事实上,链接器本身会发出警告:
$ gcc -c hello.c
$ ld -o hello hello.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
$ ./hello
Segmentation fault
使用编译器驱动程序时,它会向链接器提供一组选项和启动文件:
$ gcc -Wl,-v -o hello hello.o
collect2 version 9.3.0
/usr/bin/ld -plugin /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper -plugin-opt=-fresolution=/tmp/ccRdkBP1.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o hello /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/9 -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/9/../../.. -v hello.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
GNU ld (GNU Binutils for Ubuntu) 2.34
$ ./hello
$ echo $?
0
因此,最终的hello
二进制文件链接自Scrt1.o
,crti.o
,crtbeginS.o
,hello.o
,crtn.o
,其中大部分由编译器提供。这些是二进制工作所必需的
您的特定示例使用不同的工具,这些工具可能与此方法不兼容。这并不会使隐式规则变得“半生不熟”,并且始终欢迎您自己定义链接规则,以匹配所使用的工具集。有一个内置和定义的LD
变量,只是它不用于此隐式规则。规则本身是:
%: %.o
# recipe to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
将LINK.o
定义为
# default
LINK.o = $(CC) $(LDFLAGS) $(TARGET_ARCH)
我相信这是一条正确的道路。通常,应该调用编译器驱动程序来运行链接器(除非使用自定义链接脚本),它还包括一些编译器提供的启动文件,否则需要自己指定,这是特定于编译器的
考虑这个简单的例子:
$ cat hello.c
int main(int argc, char *argv[]) {
return 0;
}
有人可能认为这是一个完整的程序,但事实并非如此。编译它的平台需要一些额外的准备工作。事实上,链接器本身会发出警告:
$ gcc -c hello.c
$ ld -o hello hello.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
$ ./hello
Segmentation fault
使用编译器驱动程序时,它会向链接器提供一组选项和启动文件:
$ gcc -Wl,-v -o hello hello.o
collect2 version 9.3.0
/usr/bin/ld -plugin /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper -plugin-opt=-fresolution=/tmp/ccRdkBP1.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o hello /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/9 -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/9/../../.. -v hello.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
GNU ld (GNU Binutils for Ubuntu) 2.34
$ ./hello
$ echo $?
0
因此,最终的hello
二进制文件链接自Scrt1.o
,crti.o
,crtbeginS.o
,hello.o
,crtn.o
,其中大部分由编译器提供。这些是二进制工作所必需的
您的特定示例使用不同的工具,这些工具可能与此方法不兼容。这并不会使隐式规则“半生不熟”,我们欢迎您自行定义链接规则,以匹配所使用的工具集。隐式规则由POSIX提供,并“有机地增长”。如果需要,只需定义自己的规则即可。通过C编译器进行链接通常是您想要获得C运行时初始化代码的内容。这个生成文件似乎比它的价值更麻烦:/对于单个文件asm,我只使用我编写的(包含在中)nasm+ld脚本,该脚本运行nasm-felf64$1&&ld-o basename basename.o
(或带有-m32的elf32),还有一些其他选项,如添加库。或者像nasm-felf64 foo.asm和&gcc foo.o这样的一次性命令行
来组装并将一个与一个main链接。向上箭头使回忆起来的速度与make
一样快。或者control-r nasmImplicit规则是为了支持绝大多数希望在具有POSIX ish约定的POSIX ish系统上做简单简单事情的用户。想要做不寻常事情的人(直接调用链接器是不寻常的:正如@raspy所说,大多数人希望/需要编译器前端进行链接)或有不寻常的约定(POSIX编译器使用.s
和.s
进行汇编输入)需要定义自己的规则。是的,规则可以在默认情况下设置LD=$(CC)
,并使用$(LD)
,但是。。。它们没有……隐式规则是POSIX给出的,并且是“有机生长的”。如果需要,只需定义自己的规则。通过C编译器进行链接通常是您想要获得C运行时初始化代码的内容。这个生成文件似乎比它的价值更麻烦:/对于单个文件asm,我只使用我编写的(包含在中)nasm+ld脚本,该脚本运行nasm-felf64$1&&ld-o basename basename.o
(或带有-m32的elf32),还有一些其他选项,如添加库。或者像nasm-felf64 foo.asm和&gcc foo.o这样的一次性命令行
来组装并将一个与一个main链接。向上箭头使回忆起来的速度与make
一样快。或者control-r nasmImplicit规则是为了支持绝大多数希望在具有POSIX ish约定的POSIX ish系统上做简单简单事情的用户。想要做不寻常事情的人(直接调用链接器是不寻常的:正如@raspy所说,大多数人希望/需要编译器前端进行链接)或有不寻常的约定(POSIX编译器使用.s
和.s
进行汇编输入)需要定义自己的规则。是的,规则可以在默认情况下设置LD=$(CC)
,并使用