aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/development/ld.md
blob: 330395fc0f4afb86cdd80db0a698f5394c325d6a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# ld(1)

```
ld [opts] files...
    -T <script>        use <script> as linker script
    --trace            report each file the linker touches
    --start-group archives --end-group
                       search archives repearepeatedly until no new
                       undefined  references are created
                       (eg helpfull with list of static libraries)
```

## Linker Script

`output` sections are defined as follows (full description at [output
section][ld-out] and [input section][ld-in]).

```
section_name [vaddr] : [AT(paddr)] {
    file_pattern (section_pattern)
}
```

The following gives an example of an `output` section with two `input` section rules.
```
.foo : {
    abc.o (.foo)
    *.o (.foo.*)
}
```

### Example: virtual vs physical (load) address

Sometimes code is initially located at a different location as when being run.
For example in embedded cases, where code may initially resides in a _rom_ and
startup code will copy a section with writable _data_ into _ram_. Code accessing
the writable data accesses the data in the _ram_.

In this case we need different addresses for the same data.
- The `virtual` or _runtime_ address, this is the address used when the linker
  resolves accesses to the data. Hence, this is the address the data will have
  when the code is running.
- The `physical` or _load_ address, this is the address the data is stored at
  initially. Startup code typically copies the initial values from the
  `physical` to the `virtual` address.

The following shows an example linker script which uses _virtual_ and _physical_
addresses. The full source files can be found [here][src].

```
{{#include ld/link-nomem.ld}}
```

We can use the following assembly snippet to explore the linker script.

```x86asm
{{#include ld/data.S}}
```
> `gcc -c data.S && ld -o link-nomem -T link-nomem.ld data.o`

The elf load segments show the difference in _physical_ and _virtual_ address
for the segment containing the `.data` section.
```sh
> readelf -W -l link-nomem
# There are 4 program headers, starting at offset 64
#
# Program Headers:
#   Type   Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
#   LOAD   0x001100 0x0000000000800100 0x0000000000100000 0x000020 0x000020 RW  0x1000
#   LOAD   0x002000 0x0000000000800000 0x0000000000800000 0x000018 0x000018 R E 0x1000
#   LOAD   0x003000 0x0000000000804000 0x0000000000804000 0x000004 0x000004 R   0x1000
#   LOAD   0x000000 0x0000000000805000 0x0000000000805000 0x000000 0x001000 RW  0x1000
#
#  Section to Segment mapping:
#   Segment Sections...
#   00     .data
#   01     .text
#   02     .rodata
#   03     .stack
```

Startup code could copy data from `_data_paddr` to `_data_vaddr`.
```sh
> nm link-nomem
# 0000000000800100 d asm_array
# 0000000000804000 r asm_len
# 0000000000100000 a _data_paddr
# 0000000000800100 d _data_vaddr
# 0000000000800000 T _entry
# 0000000000806000 b _stack_top
```

The linker resolves symbols to their _virtual_ address, this can be seen by the
access to the `asm_array` variable.

```sh
> objdump -d link-nomem
# Disassembly of section .text:
#
# 0000000000800000 <_entry>:
#   800000:	48 c7 c4 00 60 80 00 	mov    $0x806000,%rsp
#   800007:	48 c7 c0 00 01 80 00 	mov    $0x800100,%rax   ;; mov $asm_array, %rax
#   80000e:	8b 04 25 00 40 80 00 	mov    0x804000,%eax
#   800015:	f4                   	hlt
#   800016:	eb e8                	jmp    800000 <_entry>
```

The following linker script shows an example with the `MEMORY` command.
```
{{#include ld/link-mem.ld}}
```


## References
- [ld manual][ld]
- [ld script: input sections][ld-in]
- [ld script: output sections][ld-out]
- [notes/ld example files][src]

[ld]: https://sourceware.org/binutils/docs/ld/
[ld-in]: https://sourceware.org/binutils/docs/ld/Input-Section.html
[ld-out]: https://sourceware.org/binutils/docs/ld/Output-Section-Attributes.html
[src]: https://github.com/johannst/notes/tree/master/src/development/ld