In the end, binutils have work to do on their documentation.
zaval wrote:as a conclusion, in relocatable files, DOT is assigned a difference between the CURRENT value of DOT (as it appeared in the non-relocatable case) and the FINAL value, that goes from the LAST assignment.
This applies for all files. But due to the elf specification caveats, non-relocatable files contain only absolute address-like symbol values, despite the fact that some symbols are still tagged as section relative. In any case, as you note, HaoLee observes negative offset from the beginning of the first section. The negative offset correspondingly changes if the section is moved around.
zaval wrote:Note, they claim, that DOT is just a byte offset from the current "object". Namely, - either from SECTIONS statement, or, if it is inside an output section, - from that section. In the former case, it's not described how this is related to the memory layout.
The documentation statement is misleading and the question HaoLee raised was justified. Apparently, the sentence only applies to assignments.
I am going to cite the documentation and provide my interpretation, omitting the SANE_EXPR behavior:
. always refers to a location in an output section
From which we can conclude that the location counter is a relative address. There is just no other possible interpretation. And it is consistent with the experiments I've done.
. actually refers to the byte offset from the start of the current containing object. Normally this is the SECTIONS statement, whose start address is 0, hence . can be used as an absolute address. If . is used inside a section description however, it refers to the byte offset from the start of that section, not an absolute address.
When assigning to the location counter, inside section definitions, numbers are treated as offsets, and outside, as absolute addresses.
all assignments or other statements belong to the previous output section, except for the special case of an assignment to .
the linker assumes that an assignment to . is setting the start address of a following output section and thus should be grouped with that section
This tells us that assignments to the location counter mark the start of a scope in which its value is relative to the next section.
Expressions appearing outside an output section definition treat all numbers as absolute addresses. Expressions appearing inside an output section definition treat absolute symbols as numbers.
The above sentences are important in regard to the way in which the rules apply to numbers and absolute addresses. In effect, absolute addresses are not treated as such when appearing inside a section definition. Similarly, numbers are not treated as numbers when appearing outside section definitions.
Unary operations on an absolute address or number, and binary operations on two absolute addresses or two numbers, or between one absolute address and a number, apply the operator to the value(s).
Unary operations on a relative address, and binary operations on two relative addresses in the same section or between one relative address and a number, apply the operator to the offset part of the address(es).
Other binary operations, that is, between two relative addresses not in the same section, or between a relative address and an absolute address, first convert any non-absolute term to an absolute address before applying the operator.
An operation involving only numbers results in a number.
The result of comparisons, ‘&&’ and ‘||’ is also a number.
The result of other binary arithmetic and logical operations on two relative addresses in the same section or two absolute addresses (after above conversions) is also a number when ... inside an output section definition but an absolute address otherwise.
The result of other operations on relative addresses or one relative address and a number, is a relative address in the same section as the relative operand(s).
The result of other operations on absolute addresses (after above conversions) is an absolute address.
I should add that the location counter at the start of a script is relative to the first section, and in the end of the script is relative to the last section, assuming that orphan sections are discarded.
Here is a commented example that extends the one from my previous post. The comments are based on the rules I cited from the documentation:
Code: Select all
SECTIONS
{
/* Relative address by itself results in relative address.
'.' at this point holds a negative offset to the start of custom_section,
which is yet to be determined by a future assignment to '.'
The absolute address would be 0, although if this is not the last
linker invocation, future invocations move this symbol along with the section. */
A_outside_current = .;
. = 0x111000;
/* Relative address by itself results in relative address. Still negative offset. */
B_outside_current = .;
/* Numbers treated as absolute addresses outside of sections.
Absolute address by itself results in absolute address.
This changes if LD_FEATURE ("SANE_EXPR") is requested at the start of the script. */
C_outside_direct = 0x111000;
/* Numbers treated as absolute addresses outside of sections.
Arithmetic between absolute address and relative address, converts the
relative address to absolute one and produces absolute address as well. */
D_outside_current_doubled = . * 2;
. = 0x111100;
custom_section : {
. = 0x11;
/* Relative address by itself results in relative address. 0 offset. */
E_inside_current = .;
F_inside_direct = 0x11;
/* Numbers treated as numbers inside of sections.
Arithmetic between number and relative address uses the offset of the
relative address and produces relative address. */
G_inside_current_doubled = . * 2;
/* The following are fairly clear, since they request conversion of the
address type explicitly. */
H_inside_absolute_current = ABSOLUTE(.);
I_inside_absolute_current_doubled = ABSOLUTE(.) * 2;
J_inside_absolute_E = ABSOLUTE(E_inside_current);
K_inside_absolute_H = ABSOLUTE(H_inside_absolute_current);
/* Absolute addresses are treated as numbers within sections.
Numbers produce section relative symbols in assignments. */
L_inside_H = H_inside_absolute_current;
*(.text);
. = 0x1000;
}
/* Arithmetic between relative addresses in the same section
produces absolute address, but does not convert the operands.
That is, it operates on the offset parts of the addresses. */
M_outside_current_squared = . * .;
/* Relative address in the same section produces relative address. */
N_outside_E = E_inside_current;
/* Absolute address produces absolute address as expected. */
O_outside_H = H_inside_absolute_current;
. = 0x1111100;
/* Relative address to the following section. 0 offset. */
P_in_another_section = .;
another_section : {
/* This is a surprise, although it is by the rules.
Mixing relative addresses from different sections converts them to their
absolute address value first, but produces a relative address in the end. */
Q_mixed_F_P = F_inside_direct * P_in_another_section;
LONG(0)
}
. = 0x1111111;
/* We are still in the previous section right now.
Although if orphan sections are not discarded,
we would be in one of those orphan sections instead. */
R_in_same_section = .;
/* Relative address in another section by itself is still
a relative address in that section, no matter where we use it. */
S_in_first_section = E_inside_current;
/DISCARD/ : { *(*); }
}
The results for relocatable output.
Code: Select all
ffffffffffeeef00 1 A_outside_current
ffffffffffffff00 1 B_outside_current
0000000000111000 ABS C_outside_direct
0000000000222000 ABS D_outside_current_doubled
0000000000000011 1 E_inside_current
0000000000000011 1 F_inside_direct
0000000000000022 1 G_inside_current_doubled
0000000000111111 ABS H_inside_absolute_current
0000000000222222 ABS I_inside_absolute_current_doubled
0000000000111111 ABS J_inside_absolute_E
0000000000111111 ABS K_inside_absolute_H
0000000000111111 1 L_inside_H
0000000001000000 ABS M_outside_current_squared
0000000000000011 1 N_outside_E
0000000000111111 ABS O_outside_H
0000000000000000 2 P_in_another_section
0000123455432100 2 Q_mixed_F_P
0000000000000011 2 R_in_same_section
0000000000000011 1 S_in_first_section