error: linking with `cc` failed: exit code: 1

(Reference Links: https://zhuanlan.zhihu.com/p/69393545 )

Linux

We try to prepare bare metal program under Linux, such linker errors may occur:

error: linking with `cc` failed: exit code: 1
  |
  = note: "cc" […]
  = note: /usr/lib/gcc/../x86_64-linux-gnu/Scrt1.o: In function `_start':
          (.text+0x12): undefined reference to `__libc_csu_fini'
          /usr/lib/gcc/../x86_64-linux-gnu/Scrt1.o: In function `_start':
          (.text+0x19): undefined reference to `__libc_csu_init'
          /usr/lib/gcc/../x86_64-linux-gnu/Scrt1.o: In function `_start':
          (.text+0x25): undefined reference to `__libc_start_main'
          collect2: error: ld returned 1 exit status

The problem here is that the linker will default to start the process of referencing C language runtime, or also described as _startfunction. We will use no_stda library that implements excluded under the C language standard library libc, so the linker can not resolve the relevant references, get "undefined reference" problem. To solve this problem, we need to tell the linker that it should start the process does not refer to the use of the C language - we can add -nostartfilestags to do this.

To add a parameter to the linker by cargo, we use the cargo rustccommand. The role of the command and cargo buildthe same, but allows the developer to the lower Rust compiler rustcpass parameters. Further, rustca -C link-arglabel, it is possible to pass the required parameters to the linker. In summary, we can write the following command:

cargo rustc -- -C link-arg=-nostartfiles

After this, we should be able to successfully compile the package, as a stand-alone executable program under the Linux system. Here we do not explicitly specify the name of the entry point function, because the linker will use the default function name _start.


 

Windows

In Windows system, you may have a different linker error:

error: linking with `link.exe` failed: exit code: 1561
  |
  = note: "C:\\Program Files (x86)\\…\\link.exe" […]
  = note: LINK : fatal error LNK1561: entry point must be defined

The linker error "must be defined entry points," meaning that it does not find an entry point. In the Windows system, the default entry point determined by the function name of the subsystem [1] . Of the CONSOLEsubsystem, the linker will look for named mainCRTStartupfunction; while the WINDOWSsubsystem, it will look WinMainCRTStartup. Our _startfunctions are not two names - in order to use it, we can pass to the linker /ENTRYparameters:

cargo rustc -- -C link-arg=/ENTRY:_start

From here we also see the format of the parameters, the next link in the Windows system on the use of, and under Linux are quite different.

Run the command, we got another linker errors:

error: linking with `link.exe` failed: exit code: 1221
  |
  = note: "C:\\Program Files (x86)\\…\\link.exe" […]
  = note: LINK : fatal error LNK1221: a subsystem can't be inferred and must be
          defined

This error is due to Windows executable program can use different subsystems ( the Subsystem ). General Windows programs, sub-function name used by the entry point inferred from: If the entry point is the mainfunction that will use CONSOLEthe subsystem; if it is WinMaina function, use the WINDOWSsubsystem. Since our _startfunction name and the difference between the two, we need to explicitly specify the use of the subsystem:

cargo rustc -- -C link-args="/ENTRY:_start /SUBSYSTEM:console"

Here we use the CONSOLEsubsystem, but WINDOWSthe subsystem is feasible. Here, we use a complex argument link-argsinstead of multiple -C link-arg, because the latter requires all parameters are listed in sequence, more space.

After using this command, the executable program we should be able to run under Windows.


 

macOS

If you use macOS system development, we may encounter linker errors:

error: linking with `cc` failed: exit code: 1
  |
  = note: "cc" […]
  = note: ld: entry point (_main) undefined. for architecture x86_64
          clang: error: linker command failed with exit code 1 […] 

The error message tells us that the linker can not find the default entry point function, it is named main- for some reason, all the function names macOS are to be underlined _prefix. To set the entry point to function _start, we send a link parameters -e:

cargo rustc -- -C link-args="-e __start"

-eParameter specifies the name of the entry point. Since the function under each macOS has an underscore _prefix, we should be named as the entry point function __startinstead _start.

Run this command, the emergence of such a link error now:

error: linking with `cc` failed: exit code: 1
  |
  = note: "cc" […]
  = note: ld: dynamic main executables must link with libSystem.dylib
          for architecture x86_64
          clang: error: linker command failed with exit code 1 […]

The reason is to get this error, macOS not officially supported statically linked binary library [2] , and the default program requires a link to libSystemthe library. To link to static binary library, we put -statictags to linkers:

cargo rustc -- -C link-args="-e __start -static"

Run the modified command. Linker seem satisfied, gave us throw a new error:

error: linking with `cc` failed: exit code: 1
  |
  = note: "cc" […]
  = note: ld: library not found for -lcrt0.o
          clang: error: linker command failed with exit code 1 […]

The reason for this error is that the program is linked to default on macOS crt0(C runtime zero) library. This problem encountered on Linux and similar systems, we can add a -nostartfileslink parameters:

cargo rustc -- -C link-args="-e __start -static -nostartfiles"

Now, our program should be able to successfully compiled on macOS.

Guess you like

Origin www.cnblogs.com/skzxc/p/12459713.html