Geoff Chappell - Software Analyst
SECTIONS and SEGMENTS are aliases, except that if LIB is not given the /vxd switch, SEGMENTS causes a warning (LNK4236) about being obsolete. Throughout this note, SECTIONS serves as shorthand for both.
SECTIONS is a multi-line statement. An empty statement is valid. The SECTIONS tag must run to the end of the line, else be followed by a space or tab. If the first definition is on the same line as the tag, then the space or tab may be followed by any amount of white space, including none, before the definition. Definitions other than the first must each start on a new line.
Each definition has the general form:
section_token [CLASS classname] [attributes]
The section_token extends up to but not including a space or tab (or to the end of the line). However, if this token is a recognised statement tag, then the SECTION statement is considered to have ended with the preceding definition (if any), so that the token does not name a section but is instead the beginning of a new statement.
The section_token is ordinarily the section name. However, the section may be enclosed in quotes. Specifically, if the section_token begins with either a single- or double-quote, then the section actually begins with the next character and extends up to but not including the next quote of the same type (or to the end of the token). Excess characters in the token are irrelevant and are ignored.
It is a fatal error (LNK1185) if the section contains a dollar sign. (The present coding also provides for this error if the section contains a space, but this case is impossible since a space would have terminated the section_token from which the section is taken.)
The section_token may be followed by at least one space or tab before the case-insensitive keyword CLASS or the first of the attributes (described below).
If the CLASS keyword does not end the line, it must be followed by a space or tab. There may then be any number of spaces or tabs (or single-quotes, if building for a VxD), including none, before the classname, which either ends the line or is itself followed by a space or tab (or single-quote, if building for a VxD).
The attributes complete the line. This argument is compound. Each attribute is a single case-insensitive keyword. Successive attributes are separated by spaces and tabs. The following are the recognised attributes:
CONFORMING, DISCARDABLE, EXECUTE, EXECUTEONLY, EXECUTEREAD, FIXED, IMPURE, IOPL, LOADONCALL, MOVABLE, MOVEABLE, MULTIPLE, NOIOPL, NONCONFORMING, NONDISCARDABLE, NONE, NONSHARED, PURE, PRELOAD, READ, READONLY, READWRITE, RESIDENT, SHARED, SINGLE, WRITE
It is a fatal error (LNK1118) to have anything else among the attributes.
The following attributes are recognised but not supported:
FIXED, IMPURE, LOADONCALL, MOVABLE, MOVEABLE, MULTIPLE, NOIOPL, NONCONFORMING, NONE, PURE, SINGLE
plus, if not building for a VxD:
CONFORMING, IOPL, NONDISCARDABLE, PRELOAD, RESIDENT
The presence of any of these among the attributes causes a warning (LNK4017), after which the unsupported attribute is ignored.
The following attribute is recognised but ignored without complaint:
NONSHARED
Each non-trivial definition in a non-empty SECTIONS statement is translated into a /section option for the export-file command line and also one or more /merge options if building for a VxD.
By non-trivial it is meant here that the definition provides either a classname (if building for a VxD) or at least one of the following among the attributes:
DISCARDABLE, EXECUTE, EXECUTEONLY, EXECUTEREAD, NONDISCARDABLE (if building for a VxD), PRELOAD (if building for a VxD), READ, READONLY, READWRITE, RESIDENT (if building for a VxD), SHARED, WRITE
Although CONFORMING and IOPL are supported attributes when building for a VxD, they act trivially unless given in combination with at least one of the others.
When not building for a VxD, the form for the /section option is:
/SECTION:section,[flags]
where the section in the command-line option is exactly the section from the definition. The flags are added in the following order, according to whether any of the corresponding attributes appear in the definition:
D | DISCARDABLE |
E | EXECUTE, EXECUTEONLY or EXECUTEREAD |
R | EXECUTEREAD, READ, READONLY or READWRITE |
S | SHARED |
W | READWRITE or WRITE |
Note that when not building for a VxD, classname does not contribute to the translation and is, in effect, ignored.
The classname is significant when building a VxD. The classname and attributes together name a super-section that the section is then merged into. Thus, the SECTIONS definition translates to at least the following two options for the export-file command line:
/SECTION:supersection,[flags]
/MERGE:section=supersection
where the supersection is constructed as:
[classname_]vxd[qualifiers]
The classname and underscore are included only if a classname is known from the definition. The qualifiers are added in the following order, according to whether any of the corresponding attributes appear in the definition:
p | PRELOAD |
e | EXECUTE, EXECUTEONLY or EXECUTEREAD |
r | EXECUTEREAD, READ, READONLY or READWRITE |
w | READWRITE or WRITE |
s | SHARED |
d | DISCARDABLE |
n | NONDISCARDABLE |
i | IOPL |
c | CONFORMING |
x | RESIDENT |
The flags are each added in the following order, according to whether any of the corresponding attributes appear in the definition:
D | DISCARDABLE |
E | EXECUTE, EXECUTEONLY or EXECUTEREAD |
R | EXECUTEREAD, READ, READONLY or READWRITE |
S | SHARED |
W | READWRITE or WRITE |
L | PRELOAD |
X | RESIDENT |
I | IOPL |
C | CONFORMING |
!D | NONDISCARDABLE |
The comma follows the supersection even if there are no flags to append.
If the section is recognised as a standard section for code or data in the old Object Module Format (OMF), its definition applies also to the standard section that corresponds to it in the new Common Object File Format (COFF). This is arranged by one more /merge option for the export-file command line:
/MERGE:coffsection=supersection
In the following table, the section from the definition is on the left and the corresponding coffsection is on the right.
_TEXT | .text |
_DATA | .data |
_BSS | .bss |
CONST | .rdata |
The /section and /merge options for the export-file command line are each generated in the same 128-byte buffer on the stack. The supersection (relevant only when building for a VxD) is constructed in another 128-byte buffer on the stack. None of the code checks the lengths of any strings it copies to either buffer. A sufficiently long section or classname, with sufficiently many attributes, can therefore induce an overrun and corrupt the stack, including to overwrite the relevant procedure’s return address.
In practice, of course, the section and classname are not nearly long enough to exceed these assumed limits and cause a problem. Moreover, it happens that in the version studied for these notes, namely 7.00.9466, the buffer for the command-line option runs into the buffer for the supersection, which then runs into the guard that the Buffer Security Check places before the procedure’s return address. So, except when building a VxD, the section name must be very long indeed before the overrun affects anything that matters. Still, demonstrations are easy enough.
Prepare a module definition file, named TEST.DEF, containing the following two lines:
SECTIONS 12345678901234567890...12345 EXECUTE
where the ellipsis stands for as many repetitions of 1234567890 as needed for the section argument to count to 245. With 9 bytes for the characters of the /section switch and its colon, and another two for the comma and the one-character flag that corresponds to the EXECUTE attribute, the null byte at the end of the string will be one byte too many, for both the intended 128-byte buffer and the 128-byte buffer that follows it (but which isn’t needed when not building for a VxD). Running
lib /def:test.def /machine:x86
triggers the Buffer Security Check. Repeat with section reduced by one byte, and the buffer overrun is inconsequential.
The cut-off at 245 can be lowered by adding attributes, but only to 241 (since the flags at the end of the /section switch can run only to five characters).
The same demonstration works when the /vxd switch is added to the LIB command, but with different calculations. For one thing, the ridiculously long section is added to different characters (for a /merge option, not /section). For another, the overrun of the intended 128-byte buffer now corrupts data that is still in use. Indeed, it corrupts the supersection that must yet complete the /merge option. Since the /merge switch and its colon take 7 bytes, the section need be just 121 bytes long to cause the /merge option to be generated incorrectly in the export file (however many attributes are given in the definition). Moreover, at 184 bytes, the corrupted supersection becomes large enough that completing the /merge option overruns the supersection buffer and triggers the Buffer Security Check.
The easiest triggering of the Buffer Security Check when building for a VxD is to give too long a classname, since the buffer it is used for is the higher-placed. Prepare a module definition file, again named TEST.DEF, containing the following two lines:
SECTIONS DUMMY CLASS '12345678901234567890...123' DISCARDABLE
where the ellipsis now stands for as many repetitions of 1234567890 as needed for the classname to count to 123. The supersection is formed by adding 4 bytes for the characters of _vxd and 1 byte for the one-character qualifier that corresponds to the DISCARDABLE attribute. The null byte at the end of the string will be one byte too many for the 128-byte buffer. Running
lib /def:test.def /machine:x86 /vxd
triggers the Buffer Security Check. Repeat with a longer classname, and the buffer overrun persists. Repeat with classname reduced to 122 bytes, and there is no buffer overrun.