MC ELF doesn't allow a section with the same name as a label

As many of you know, we’re using LLVM for the port of OpenVMS to x86. We are now bootstrapping our Itanium-hosted cross-compilers to native OpenVMS x86 systems. So far, we’ve adjusted to catching up on several years of minor changes to the API. However, we just hit a big one!

For legacy reasons, I won’t bore you with, our C compiler wants to create static variables in a section with the same name. That works fine on our Itanium ELF-based systems (our own backend) and with the LLVM 3.4.2 cross-compilers. However, LLVM 5 rototilled that code and there is now a check for duplicate names. This one is hard for us to workaround. OpenVMS exposes sections (aka PSECTs) at a greater level than you see on Windows or UNIX systems so we really can’t just uniquify the names.

Reading the original gabi41.pdf spec and the current at http://www.sco.com/developers/gabi/latest, I see no requirement that sections and symbols are in the same namespace. Sections have names and an index. Symbols have names and a section index. Since the namespaces between PSECTs and symbols are separate, OpenVMS allows you to have a routine named CODE that is placed in a PSECT named CODE and has done so since 1977 (of course not using ELF way back then)

3.4.2 [MC/ELFObjectWriter.cpp] simply looped over the sections and wrote them into the ELF symbol table with no name and STT_SECTION.

The new 5.0 code [MC/MCContext.cpp], now checks for name duplication at section creation but still writes out sections into the symbol table with no name and STT_SECTION. This synthetic merging of the name spaces doesn’t make sense to me and seems wrong.

I understand that I’m fighting against years of status quo (and all the binutils I tried don’t allow it either) but we’re stuck on this one. I can’t undo 40 years of OpenVMS legacy programs and linker options.

Here’s a quick example written in assembler https://godbolt.org/z/1oE8aW934 Compiles with 4.0.1, does not with 5.0 or later.

Any suggestions or background on such a change? (other than early retirement) The comment in the 5.0 edit didn’t give enough context to understand the rationale.

When you define a section, the assembler automatically generates a symbol with the name of that section. For example:

.section    x,"aw"
.byte . - x
.byte . - x

It would probably be reasonable to add some way to suppress that symbol.

But such a symbol would be …x$$base… or some other name unlikely to be also used by the user (which is what my legacy VAX assembler would do). I hope they wouldn’t just use the name of the section as the name of the symbol.

Previous post accidentally deleted, and I don’t see an “undo.” Here it is again:

Well, for an ELF target, yes. This:
int SECTION __attribute__((section("SECTION"))) = 0;
compiles cleanly when targeting Windows, but gets an error targeting Linux. That seems kinda wrong.

The symbol is getting emitted, whether or not you think it’s a silly idea. And as long as the symbol is getting emitted, we have to emit an error if the user attempts to redefine it.

If you want the assembler to skip emitting this symbol, you’ll need to propose new syntax of some sort (a new form of .section, or a .disable_section_name_symbols directive, or something like that).

I would have thought the decision could be based on the triple too/instead of a directive if there’s no history of actually using the section as a symbol on OpenVMS.

That too, sure.

The GNU as error Error: symbol SECTION’ is already defined` has a value to prevent fragile use errors.
Modern integrated assembler does the right thing to follow suit.
STT_SECTION symbols are valuable in that they can be referenced by relocations and greatly decrease the number of local symbols (by redirecting local symbols to the relevant STT_SECTION).
The auto-defined local symbol gives the user a way to serialize such representations into assembly.
(PE/COFF unfortunately does not have the feature.)
I’ll be a bit sad if some ELF target wants to customize this and bypass the error.

Are your porting an object file format to ELF? It feels odd to me that you cannot mangle section names in a way to not conflict with symbol names, to avoid the issue. An ELF section name can be any NUL-terminated string, with no length limit.

Wait, there is still a way without losing the diagnostic, if you cannot mangle your section names. We can invent a directive to rename a symbol.

.section SECTION,"a",%progbits
.globl SEC
.type SEC, %object
SEC:
.rename SEC, SECTION

Actually, .symver should have been implemented with such semantics but GNU folks somewhat borked it.

Let me tweak the example slightly:

.section SECTION,"a",%progbits
.long 0 # other stuff at the top of the section
.globl SEC
.type SEC, %object
SEC:
.rename SEC, SECTION

Now the two SECTION symbols don’t have the same value. When there is a symbolic reference to SECTION, which does it use–the renamed object, or the section? Within the encoded representation used by MC, I think the symbols are still distinct, but it’s less clear what happens after the assembly is serialized into a text file and read back in.

The problem here isn’t really that the symbol exists, I guess… it’s that the symbol has a name which conflicts with a name the user wants to use for something else. Some way to rename it (independent of the name of the section) would be sufficient.

We use ELF on Itanium. The namespaces are distinct. I have little sympathy for assembly writers (or compilers). Consider the following assembly:

You can legally write

a:  .long 0
     .section a, "a", @progbits
b:  .long 0

and you can legally write

    .section a, "a", @progbits
a:  .long 0

(well, not since LLVM 5).

I complete understand a compiler generating a synthetic name of the section base so it can use it in various relocations. We do it all the time. You can’t refer to a section with a relocation, only a symbol.

However, our linker does provide mechanisms to change attributes of sections at link time (ie, making sections no-execute or no-write without having to recompile). OpenVMS’s COMMON block model is with sections and not symbols (I don’t want to confuse the issue here however). We often wrap static variables in such a self-named section for legacy compatibility with customer tools and link scripts.

Looking at one of the original changes https://reviews.llvm.org/D30235 it seems the XCore backend had some problems so the author found the biggest hammer around and make the source code illegal. It isn’t illegal to have a routine that uses the same name as a section.

The STT_SECTION symbols do not have a symbol name. There is no conflict.

A few more points:

Our legacy GEM backend does (did?) this on Linux (symbol and section with same name). It did it also on our Tru64 UNIX systems.

I’ve taken objects from my cross-compiler (symbol and section with same name) to my nearby RHEL system and it seems to link just fine.

I found the “I’ll be a bit sad if some ELF target wants to customize this and bypass the error.” statement to be a bit dismissive of my position. The need is due to historical legacy behavior dating back to the VAX systems in 1977 (and PDP-11 RSX systems prior). Of course, those were not ELF but the symbol vs section (called PSECTs in that model) have separate name spaces. It is legal ELF. Having an assembler flag it as a programming aid is different than making it illegal.

I understand the benefit for referring to the STT_SECTION in the symbol table. But it has no name (and still doesn’t). Look at the output from today’s LLVM (a simple hello world) and you see an STT_SECTION with a name index of 0 (ie, no name) and an shndx of the correspond section.

$ readelf -s hw.o

Symbol table '.symtab' contains 6 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hw.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    2
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    4
     4: 0000000000000000    38 FUNC    GLOBAL DEFAULT    2 main
     5: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND printf

Looking at the code, LLVM never emits a name in the STT_SECTION symbols. I use readelf since objdump tricks you into thinking the STT_SECTION was given a name, it was not.

Whether or how we actually emit a symbol into the object file isn’t really relevant. The important part is that the name exists in the assembler’s symbol table. That fundamentally conflicts with any other use of the name in assembly.

I see the follow possibilities, broadly speaking:

  1. We decide that we don’t need to be compatible with the GNU assembler, and just remove the section name from the assembler’s symbol table.
  2. We add some way for the user to explicitly indicate they want to use the section name for something else.
  3. If the user defines a symbol, we treat that as implicitly indicating the user wants to use the section name for something else. (We did this in some cases before D30235, I think, but it didn’t work reliably.)
  4. We don’t allow the user to define a symbol with the same name as a section. (This is the status quo.)

Along with any of those options, we can add some other way to refer to the section.

“We decide that we don’t need to be compatible with the GNU assembler” is not happening, at least on GNU targets. And implicitly changing the meaning of a symbol reference is, at best, confusing. So we’re left with either doing nothing, or adding a new assembler directive.

I see justification that there is (sometimes) a need for a user-variable-namespace symbol to refer to the beginning of a section, but I haven’t seen any justification for that name to be identical to the section name with no provision for a distinguishing prefix, suffix, name-mangling, or any other way to keep it distinct from names of the user-code variables. There’s nothing in the language standards for C nor C++ (nor any other language with which I’m familiar) to require section names be distinct from variable names.
I’ve been doing software engineering for decades but I’m new to LLVM, so please educate me. Is there something else that has induced this connection, or was it just super easy to use the same name and no one complained until now?

Then the assembler is broken. It needs to know there are two namespaces. An assembler would have to keep track of things like macro argument names being visible in the macro body but not elsewhere. Having scoped and segregated names is very common.

When mentioning the section as a reference (not a symbol), it is ambiguous to me. Do you want the address of the module’s contribution to the image or the start of the final combined section after the linker is finished collecting them all?

I’ll argue about the status quo. Please give me the reference from the ABI that disallows it. There is none. We’ve been using this on Itanium Linux ELF for years with our legacy backend and the standard distribution linker.

And this GNU compatibility is about flagging certain uses as errors. It isn’t allowing any sort of new functionality. Removing the errors and doing it correctly wouldn’t break any compatibility.

We’ve ported an entire OS and eco-system (and customers have ported applications) using our LLVM 3.4.2 based cross-compilers. Works great. I no longer can provide such compilers running natively using a more modern LLVM. One way or the other, we’ll have to do something.

Sometimes it is the status quo, and sometimes not. Depends on the target, as I noted upthread.

@JohnReagan is OpenVMS a GNU target? Or a non-GNU target that happens to want to use ELF?

We set GNU_TARGET but there are features that OpenVMS doesn’t support (like fork()). At the ELF level, there are some section flags that are ignored like SHF_MERGE. We do COMMON a little different (which is related to this issue but I didn’t want to confuse the issue). We added support for .init_array and more support for UNIX weak in our compiler tools. [Again, I don’t want to confuse the issue with the fact that OpenVMS has two forms of weak. It isn’t important here.]

Overnight, I’ve consulted with a few other co-workers and all seem to think that there are two name spaces and it is perfectly valid for a section to have the same name as a symbol. We all agree that two symbols cannot have the same name.

I’m not understanding the GNU compatibility aspect. GNU doesn’t allow it so we changed to also not allow it? Adding the error message doesn’t add any functionality. It removes it.

The edit I pointed at yesterday seemed to be “fixing” a bug report about a C/C++ source that wanted to name a function with the same name as one of the target sections (which might be different on different targets). I’m talking at the assembly level to not mix in any language issues. All of those I can deal with.

This really has the feel of an internal implementation detail, in that the actual name of the section in the assembler’s symbol table is not important–all that matters is that there is a symbol. I don’t see why an implementation detail about that symbol’s name should introduce a user-facing error. This tells me that GNU as has a bug, and it should use some non-user-visible name for this section symbol. Seems like we should be able to fix this bug wrt the name, and still preserve the functionality of relocations against the section symbol.