Date created: 04/21/19 16:06:24. Last modified: 06/03/19 08:05:34

Assembling and Linking (gcc)

Compile C to assembly, then compile and link assembly in a single step:


$ cat hello_world.c
#include <stdio.h>

int main(void) {
printf("Hello, world!\n");
return 0;
}

# Compile C code to assembly (.s) file:
$ gcc -S -m64 -masm=intel hello_world.c

$ file hello_world.s
hello_world.s: assembler source, ASCII text

$ cat hello_world.s

.file "hello_world.c"
.intel_syntax noprefix
.text
.section .rodata
.LC0:
.string "Hello, world!"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
lea rdi, .LC0[rip]
call [email protected]
mov eax, 0
pop rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0"
.section .note.GNU-stack,"",@progbits

# Compile assembly into object (.o) file as machine code, and link into binary executable.
# This one gcc command calls `as` to compile and then `ld` to link in one command:
$ gcc -o hello_world -m64 hello_world.s

$ file hello_world
hello_world: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=7b99531e675d43c0d8c674076b910c2c60dcd8a8, not stripped

$ ./hello_world
Hello, world!
$ echo $?
0

Compile C to assembly, then compile and link assembly in a separate steps:


# Alternatively, from the generated (.s) assembly code file,
# perform the steps seperately:
$ gcc -S -m64 -masm=intel hello_world.c # Produces .s assembly code

$ file hello_world.s
hello_world.s: assembler source, ASCII text

# Compile the linked assembly into an object (.o) file with machine code:
gcc -g -c hello_world.s

$ file hello_world.o
hello_world.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), with debug_info, not stripped

# Optionlly dump the machine code:
$ objdump -d -M intel -S hello_world.o

hello_world.o: file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
push rbp
0: 55 push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
1: 48 89 e5 mov rbp,rsp
.cfi_def_cfa_register 6
lea rdi, .LC0[rip]
4: 48 8d 3d 00 00 00 00 lea rdi,[rip+0x0] # b <main+0xb>
call [email protected]
b: e8 00 00 00 00 call 10 <main+0x10>
mov eax, 0
10: b8 00 00 00 00 mov eax,0x0
pop rbp
15: 5d pop rbp
.cfi_def_cfa 7, 8
ret
16: c3 ret


# Then link into an executable:
$ gcc -g hello_world.o -o hello_world

$ file hello_world
hello_world: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=4f046a79f6957a2c47ac7ac5ff7b156147c2e4b4, with debug_info, not stripped

$ ./hello_world
Hello, world!
$ echo $?
0