Assembly 为什么';不能为隐式规则定义LD变量吗?

Assembly 为什么';不能为隐式规则定义LD变量吗?,assembly,makefile,gnu-make,Assembly,Makefile,Gnu Make,我目前正在学习组装。我编写了简单的测试程序,因此我编写了一个简单的makefile: AS = nasm CC = ld

我目前正在学习组装。我编写了简单的测试程序,因此我编写了一个简单的makefile:

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)
,并使用