If I issue the command gcc hello.s in the ubuntu terminal, will the assembly code be linked with a C library as someone in a webpage contends?
Yes.
And if yes, why is that?
That's the documented default behavior of the gcc
command when linking, because it's intended primarily for C programs.
The assembly code doesn't seem to refer to C code anywhere.
It doesn't matter, because the assembler and linker don't check whether it does or not.
The default behavior is to set up a link involving the C library, its standard startup code, and your code. You can see the details if you run gcc -v hello.s
:
/usr/lib/gcc/x86_64-linux-gnu/9/collect2 -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/ccVrfSjS.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 /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/../../.. /tmp/cc17H49O.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
The crt*.o
files are startup code, and -lc
links the C library.
In a C program, the standard startup code is supposed to be the first thing that runs, in order to initialize the library and set up various things in the way that compiled C code expects. So it defines the _start
label which is used as the program's entry point, and it contains a call to a symbol called main
. Therefore the link can only succeed if the code you supply does define a symbol called main
, and does not define a symbol called _start
(because there are not allowed to be two, or the linker would not know which to use). That is not the case for your code, on either count.
If you want some other behavior, it's determined by command line switches, not by the contents of your code. -nostdlib
tells the linker not to include the C library and its startup code; in that case, your code must supply _start
and main
is not required. So if you compile with gcc -nostdlib -no-pie foo.s
, your code compiles and runs succesfully.
(The -no-pie
option is needed because your code uses an absolute static address as an immediate, in mov $message, %rsi
. These are limited to 32 bits and so cannot work if the code is to be relocated to an arbitrary spot in the 64-bit address space. Better practice is to use RIP-relative addressing: lea message(%rip), %rsi
, and then you won't need -no-pie
. You can also use a form of mov
with a 64-bit immediate, movabs $message, %rsi
, but it uses a few more bytes of code.)