The two numbers are wildly different, and I don't understand how to reconcile them.
Hint appreciated please!
The zpool
output is correct.
The other command you might be interested in is zfs list
.
This really boils down to the author’s opinion, in my opinion.
In the FreeBSD (“Unix”) convention, you push the arguments on the stack, specify the system call number in EAX
, and invoke interrupt 0x80 (with an extra operand on the stack because it expects to be called from a separate function).
In the Linux i386 convention, you place the arguments in the appropriate registers, and invoke interrupt 0x80.
The bulky/slow argument presumably comes from the fact that with the Linux convention, the caller needs to deal with its use of registers. If the system call needs arguments in registers that contain values the caller cares about, it needs to preserve them, which results in additional legwork; see this example from the C library. In this example, the system call needs values in EAX, EBX, EDX, EDI, and ESI; but the caller only cares about preserving EBX, EDI, and ESI, so it only pushes those to the stack. The general case is quite a bit more complex (but that’s also the result of dealing with a mixture of C and assembly language, trying to generate optimal code in all cases), however when writing in assembly language, which is the point of the site you’re referring to, that wouldn’t be as much of an issue.
It seems to me that it’s six and half-a-dozen: in the FreeBSD convention, you push to the stack in all cases, in the Linux convention, you push to the stack (or elsewhere) depending on what you’re doing around the call site. You could argue that the Linux convention enables faster code since you can perform all your calculations in registers... As Rob points out however, on Linux the registers still end up being pushed (to build the struct pt_regs
instance which is used to provide the arguments to the C functions which deal with the system calls), so the overall cost is greater on the Linux side than on the FreeBSD side.
In any case arguing about performance when talking about stack or register-based code around a system call seems rather pedantic, given the cost of performing the system call itself. Any cycle saved is of course good in absolute terms, but the relative improvement will be tiny.
Best Answer
It seems you need to add
-z noexecstack
(This was added for ELF binaries as well in LLD 7.0.0). The default is to have an executable stack region which is vulnerable to exploitation via stack memory. Your binary image does not have an executable stack and I believe that is why it fails. The error throws you off as it asks you to tell what target emulation to use for your stack (which you do not have).David Herrmann did all the hard work and have found a cross platform solution which covers:
The magic invocation is then:
And most often you want that binary segment to be read-only:
UPDATE:
I could not test as my system was:
I spun up a VM with FreeBSD 12.0 to test this out and found this:
The
-z noexecstack
was only added in 7.0.0 and it is not listed in the man page for 6.0.1. More annoyingly specifying unsupported values for-z
does not trigger an error!I have not upgraded to LLVM 7 to test if that does the trick. @Richard Smith found a proper solution himself by specifying the emulation with
-m
in another answer. That route would be so much easier if LLD listed supported emulations with-V
.If you use the
file
command onfile.o
you will see it identifies as SYSV ELF. This might be good enough for you. But if you want the exact samme as the system then useelf_amd64_fbsd
which is an alias forelf_x86_64_fbsd
. Annoyinglyld -V
does not output supported emulations with LLD as GNU ld does.elf_amd64_fbsd
is an alias forelf_x86_64_fbsd
(see D7837 and D24356). Hopefully LLD will add the emulations to the-V
output.