I tried to cover asm to hex by gcc ( gcc -c -masm=intel code.s) by it error: code.s:1: Error: too many memory references for `mov'.
code.s asm:
mov rax , 0x00000000004007E6
js rax
what happened? Can you tutorial me cover it?
As Margaret Bloom said, -masm=intel is only a code generation option, meaning it affects what kind of assembly the compiler generates from C code. It does not affect assembling at all.
You need to put .intel_syntax noprefix directive in your assembly file to switch syntax, or use the convoluted gcc -Wa,--msyntax=intel,-mnaked-reg method to pass argument to the assembler.
Having done the above, the next issue will be that js rax is invalid as there is no conditional indirect jump in x86. The easiest will be probably to use a reversed condition, jns, to skip over a jmp rax.
Related
I have this piece of inline assembly code that should print A in text mode:
void print(){
asm volatile(
"mov ax,0xb800\n"
"mov ds,ax\n" /*<-as complains about this*/
"movb 0,'A'\n"
);
}
However when I try to compile it with gcc(with -m32 and -masm=intel):
./source/kernel.c: Assembler messages:
./source/kernel.c:4: Error: invalid instruction suffix for `mov'
btw this piece of code is from my operating system's kernel, so I can't use stdio.h or something like that.
Despite GCC's line numbering in the error message, that's not the line it's actually complaining about, it's the movb store. You can test that by commenting the other instructions. The error is actually printed by the assembler, with numbering based on .loc metadata directives from the compiler, and this is a multi-line asm template, so it's easy for that to go wrong I guess.
I suspect GAS .intel_syntax mode treats a literal 0 as an immediate, for consistency with mov al, 0 with 0 as a source operand. This of course can't work as a destination.
The "invalid instruction suffix" error message makes little sense, although note that Intel syntax doesn't use operand-size suffixes. (For some reason movb [0], 'A' is accepted, though.)
Instead use square brackets to avoid ambiguity; recommended for any memory operand, even if the address is a symbol instead of a literal number.
mov byte ptr [0], 'A'
mov byte ptr ds:0, 'A' also works, and is the syntax objdump -d -Mintel uses.
It's a good idea to always use square brackets on memory operands to remove any ambiguity, especially for people who might be used to the NASM flavour of Intel syntax.
I am trying to include a header file containing a macro into my main assembly file, but the compilation fails.
Below is my main.S file
#include "common.h"
BEGIN
mov $0x0E40, %ax
int $0x10
hlt
Below is my common.h file :
.macro BEGIN
LOCAL after_locals
.code16
cli
ljmp $0, $1f
1:
xor %ax, %ax
/* We must zero %ds for any data access. */
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %bp
/* Automatically disables interrupts until the end of the next instruction. */
mov %ax, %ss
/* We should set SP because BIOS calls may depend on that. TODO confirm. */
mov %bp, %sp
/* Store the initial dl to load stage 2 later on. */
mov %dl, initial_dl
jmp after_locals
initial_dl: .byte 0
after_locals:
.endm
Both files are in same directory. When I do the compilation :
$ as --32 -o main.o main.S
main.S: Assembler messages:
main.S:2: Error: no such instruction: `begin'
What am I missing? I did a little research and got this answer in SO, but its not helpful. Please help.
$ as --32 -o main.o main.S
as is just an assembler, it translates assembly source to object code. It does not run the C preprocessor which is supposed to expand #include.
(# is the comment character in GAS syntax for x86 so the line is treated as a comment if it's seen by the assembler instead of replaced by CPP)
What you can do:
Use gcc to assemble, with appropriate file suffix (.S or .sx), it will run the C preprocessor before running the assembler.
Add -v to see what commands gcc is invoking.
If your source has a different suffix, you can -x assembler-with-cpp source.asm.
If you want to see the intermediate result after preprocessing, add -save-temps. This will write a .s file with the preprocessed source.
If you want to pass down a command line option to as, you can for example -Wa,--32. However, it is better to use options which the compiler driver understands like -m32 or -m16 in the present case. The driver knows about such options, for example it will also cater for appropriate options when linking, provided you are linking with gcc -m32 ... as noted below.
Use a .include assembler directive which is handled by the assembler itself, not the C preprocessor.
Note: In case 1. adding include search paths by means of -I path might not work as expected: The compiler driver (gcc in this case) will add -I path only to the assembler's command line if it knows that it's the GNU assembler. You can tell this when the compiler is configured by configure flag --with-gnu-as.
Note: Similar applies to linking. You probably do not want to call the linker (ld by hand) unless you're making a static executable or flat binary; use gcc or g++ instead if you're making a normal executable to run on the host system. It will add many options needed for linking like multilib paths, search paths, etc. which you do not want to fiddle by hand.
(int $0x10 is a 16-bit BIOS call, though, which won't work under a modern mainstream OS, only DOS or a legacy BIOS bootloader.)
If your header file is just assembly then include with .include "file" directive in main.S. But this way of doing would insert the code the location where its included.
I have the following code which compiles fine with the gcc command gcc ./example.c. The program itself calls the function "add_two" which simply adds two integers. To use the intel syntax within the extended assembly instructions I need to switch at first to intel and than back to AT&T. According to the gcc documentation it is possible to switch to intel syntax entirely by using gcc -masm=intel ./exmaple.
Whenever I try to compile it with the switch -masm=intel it won't compile and I don't understand why? I already tried to delete the instruction .intel_syntax but it still don't compile.
#include <stdio.h>
int add_two(int, int);
int main(){
int src = 3;
int dst = 5;
printf("summe = %d \n", add_two(src, dst));
return 0;
}
int add_two(int src, int dst){
int sum;
asm (
".intel_syntax;" //switch to intel syntax
"mov %0, %1;"
"add %0, %2;"
".att_syntax;" //switch to at&t syntax
: "=r" (sum) //output
: "r" (src), "r" (dst) //input
);
return sum;
}
The error message by compiling the above mentioned program with gcc -masm=intel ./example.c is:
tmp/ccEQGI4U.s: Assembler messages:
/tmp/ccEQGI4U.s:55: Error: junk `PTR [rbp-4]' after expression
/tmp/ccEQGI4U.s:55: Error: too many memory references for `mov'
/tmp/ccEQGI4U.s:56: Error: too many memory references for `mov'
Use -masm=intel and don't use any .att_syntax directives in your inline asm. This works with GCC and I think ICC, and with any constraints you use. Other methods don't. (See Can I use Intel syntax of x86 assembly with GCC? for a simple answer saying that; this answer explores exactly what goes wrong, including with clang 13 and earlier.)
That also works in clang 14 and later. (Which isn't released yet but the patch is part of current trunk; see https://reviews.llvm.org/D113707).
Clang 13 and earlier would always use AT&T syntax for inline asm, both in substituting operands and in assembling as op src, dst. But even worse, clang -masm=intel would do that even when taking the Intel side of an asm template using dialect-alternatives like asm ("add {att | intel}" : ... )`!
clang -masm=intel did still control how it printed asm after its built-in assembler turned an asm() statement into some internal representation of the instruction. e.g. Godbolt showing clang13 -masm=intel turning add %0, 1 as add dword ptr [1], eax, but clang trunk producing add eax, 1.
Some of the rest of this answer talking about clang hasn't been updated for this new clang patch.
Clang does support Intel-syntax inside MSVC-style asm-blocks, but that's terrible (no constraints so inputs / outputs have to go through memory.
If you were hard-coding register names with clang, -masm=intel would be usable (or the equivalent -mllvm --x86-asm-syntax=intel). But it chokes on mov %eax, 5 in Intel-syntax mode so you can't let %0 expand to an AT&T-syntax register name.
-masm=intel makes the compiler use .intel_syntax noprefix at the top of its asm output file, and use Intel-syntax when generating asm from C outside your inline-asm statement. Using .att_syntax at the bottom of your asm template breaks the compiler's asm, hence the error messages like PTR [rbp-4] looking like junk to the assembler (which is expecting AT&T syntax).
The "too many operands for mov" is because in AT&T syntax, mov eax, ebx is a mov from a memory operand (with symbol name eax) to a memory operand (with symbol name ebx)
Some people suggest using .intel_syntax noprefix and .att_syntax prefix around your asm template. That can sometimes work but it's problematic. And incompatible with the preferred method of -masm=intel.
Problems with the "sandwich" method:
When the compiler substitutes operands into your asm template, it will do so according to -masm=. This will always break for memory operands (the addressing-mode syntax is completely different).
It will also break with clang even for registers. Clang's built-in assembler does not accept %eax as a register name in Intel-syntax mode, and doesn't accept .intel_syntax prefix (as opposed to the noprefix that's usually used with Intel-syntax).
Consider this function:
int foo(int x) {
asm(".intel_syntax noprefix \n\t"
"add %0, 1 \n\t"
".att_syntax"
: "+r"(x)
);
return x;
}
It assembles as follows with GCC (Godbolt):
movl %edi, %eax
.intel_syntax noprefix
add %eax, 1 # AT&T register name in Intel syntax
.att_syntax
The sandwich method depends on GAS accepting %eax as a register name even in Intel-syntax mode. GAS from GNU Binutils does, but clang's built-in assembler doesn't.
On a Mac, even using real GCC the asm output has to assemble with an as that's based on clang, not GNU Binutils.
Using clang on that source code complains:
<source>:2:35: error: unknown token in expression
asm(".intel_syntax noprefix \n\t"
^
<inline asm>:2:6: note: instantiated into assembly here
add %eax, 1
^
(The first line of the error message didn't handle the multi-line string literal very well. If you use ; instead of \n\t and put everything on one line the clang error message works better but the source is a mess.)
I didn't check what happens with "ri" constraints when the compiler picks an immediate; it will still decorate it with $ but IDK if GAS silently ignores that, too, in Intel syntax mode.
PS: your asm statement has a bug: you forgot an early-clobber on your output operand so nothing is stopping the compiler from picking the same register for the %0 output and the %2 input that you don't read until the 2nd instruction. Then mov will destroy an input.
But using mov as the first or last instruction of an asm-template is usually also a missed-optimization bug. In this case you can and should just use lea %0, [%1 + %2] to let the compiler add with the result written to a 3rd register, non-destructively. Or just wrap the add instruction (using a "+r" operand and an "r", and let the compiler worry about data movement.) If it had to load the value from memory anyway, it can put it in the right register so no mov is needed.
PS: it's possible to write inline asm that works with -masm=intel or att, using GNU C inline asm dialect alternatives. e.g.
void atomic_inc(int *p) {
asm( "lock add{l $1, %0 | %0, 1}"
: "+m" (*p)
:: "memory"
);
}
compiles with gcc -O2 (-masm=att is the default) to
atomic_inc(int*):
lock addl $1, (%rdi)
ret
Or with -masm=intel to:
atomic_inc(int*):
lock add DWORD PTR [rdi], 1
ret
Notice that the l suffix is required for AT&T, and the dword ptr is required for intel, because memory, immediate doesn't imply an operand-size. And that the compiler filled in valid addressing-mode syntax for both cases.
This works with clang, but only the AT&T version ever gets used.
Note that -masm= also affects the default inline assembler syntax:
Output assembly instructions using selected dialect. Also affects
which dialect is used for basic "asm" and extended "asm". Supported
choices (in dialect order) are att or intel. The default is att.
Darwin does not support intel.
That means that your first .intel_syntax directive is superfluous and the final .att_syntax is wrong because your GCC call compiles C to Intel assembler code.
IOW, either stick to -masm=intel or sandwich your inline Intel assembler code sections between .intel_syntax noprefix and .att_syntax prefix directives - but don't do both.
Note that the sandwich method isn't compatible with all inline assembler constraints - e.g. a constraint that involves m (i.e. memory operand) would insert an operand in ATT syntax which would yield an error like 'Error: junk (%rbp) after expression'. In those cases you have to use -masm=intel.
Now that i know u can use gcc for Intel syntax instead of default at&t with
gcc -S -masm=intel test.c
There is this line
mov DWORD PTR [ebp-16], OFFSET FLAT:base
Is it the same as mov dword[ebp-16], base?
Otherwise what must i do?
Yes, mov dword [ebp - 16], base is correct NASM syntax to store the label address to 4 bytes of memory at EBP-16.
I haven't seen offset flat: for a while - I think it's obsolete, but it's what GAS's idea of .intel_syntax noprefix used to demand (I had to look at Gas's source code to find that out). gcc -masm=intel uses it when using symbol addresses as immediates, but offset base works, too, in GAS.
It means the same as offset to MASM, or the unadorned variable name in NASM.
I'm trying to create a Shared library (*.so) in ASM and I'm not sure that i do it correct...
My code is:
.section .data
.globl var1
var1:
.quad 0x012345
.section .text
.globl func1
func1:
xor %rax, %rax
# mov var1, %rcx # this is commented
ret
To compile it i run
gcc ker.s -g -fPIC -m64 -o ker.o
gcc ker.o -shared -fPIC -m64 -o libker.so
I can access variable var1 and call func1 with dlopen() and dlsym() from a program in C.
The problem is in variable var1. When i try to access it from func1, i.e. uncomment that line, the compiler generates an error:
/usr/bin/ld: ker.o: relocation R_X86_64_32S against `var1' can not be used when making a shared object; recompile with -fPIC
ker.o: could not read symbols: Bad value
collect2: ld returned 1 exit status
I don't understand. I've already compiled with -fPIC, so what's wrong?
I've already compiled with -fPIC, so what's wrong?
That part of the error message is for people who are linking compiler-generated code.
You're writing asm by hand, so as datenwolf correctly wrote, when writing a shared library in assembly, you have to take care for yourself that the code is position independent.
This means file must not contain any 32-bit absolute addresses (because relocation to an arbitrary 64-bit base is impossible). 64-bit absolute relocations are supported, but normally you should only use that for jump tables.
mov var1, %rcx uses a 32-bit absolute addressing mode. You should normally never do this, even in position-dependent x86-64 code. The normal use-cases for 32-bit absolute addresses are: putting an address into a 64-bit register withmov $var1, %edi (zero-extends into RDI)
and indexing static arrays: mov arr(,%rdx,4), %edx
mov var1(%rip), %rcx uses a RIP-relative 32-bit offset. It's the efficient way to address static data, and compilers always use this even without -fPIE or -fPIC for static/global variables.
You have basically two possibilities:
Normal library-private static data, like C compilers will make for __attribute__((visibility("hidden"))) long var1;, same as for -fno-PIC.
.data
.globl var1 # linkable from other .o files in the same shared object / library
.hidden var1 # not visible for *dynamic* linking outside the library
var1:
.quad 0x012345
.text
.globl func1
func1:
xor %eax, %eax # return 0
mov var1(%rip), %rcx
ret
full symbol-interposition-aware code like compilers generate for -fPIC.
You have to use the Global Offset Table. This is how a compiler does it, if you tell him to produce code for a shared library.
Note that this comes with a performance hit because of the additional indirection.
See Sorry state of dynamic libraries on Linux for more about symbol-interposition and the overheads it imposes on code-gen for shared libraries if you're not careful about restricting symbol visibility to allow inlining.
var1#GOTPCREL is the address of a pointer to your var1, the pointer itself is reachable with rip-relative addressing, while the content (the address of var1) is filled by the linker during loading of the library. This supports the case where the program using your library defined var1, so var1 in your library should resolve to that memory location instead of the one in the .data or .bss (or .text) of your .so.
.section .data
.globl var1
# without .hidden
var1:
.quad 0x012345
.section .text
.globl func1
func1:
xor %eax, %eax
mov var1#GOTPCREL(%rip), %rcx
mov (%rcx), %rcx
ret
See some additional information at http://www.bottomupcs.com/global_offset_tables.html
An example on the Godbolt compiler explorer of -fPIC vs. -fPIE shows the difference that symbol-interposition makes for getting the address of non-hidden global variables:
movl $x, %eax 5 bytes, -fno-pie
leaq x(%rip), %rax 7 bytes, -fPIE and hidden globals or static with -fPIC
y#GOTPCREL(%rip), %rax 7 bytes and a load instead of just ALU, -fPIC with non-hidden globals.
Actually loading always uses x(%rip), except for non-hidden / non-static vars with -fPIC where it has to get the runtime address from the GOT first, because it's not a link-time constant offset relative to the code.
Related: 32-bit absolute addresses no longer allowed in x86-64 Linux? (PIE executables).
A previous version of this answer stated that the DATA and BSS segments could move relative to TEXT when loading a dynamic library. This is incorrect, only the library base address is relocatable. RIP-relative access to other segments within the same library is guaranteed to be ok, and compilers emit code that does this. The ELF headers specify how the segments (which contain the sections) need to be loaded/mapped into memory.
I don't understand. I've already compiled with -fPIC, so what's wrong?
-fPIC is a flag concerning the creation of machine code from non-machine code, i.e. which operations to use. In the compilation stage. Assembly is not compiled, though! Each assembly mnemonic maps directly to a machine instruction, your code is not compiled. It's just transcribed into a slightly different format.
Since you're writing it in assembly, your assembly code must be position independent to be linkable into a shared library. -fPIC has not effect in your case, because it only affects code generation.
Ok, i think i found something...
First solution from drhirsch gives almost the same error but the relocation type is changed. And type is always ended with 32. Why is it? Why 64 bit program uses 32-bit relocation?
I found this from googling: http://www.technovelty.org/code/c/relocation-truncated.html
It says:
For code optimisation purposes, the default immediate size to the mov
instructions is a 32-bit value
So that's the case. I use 64-bit program but relocation is 32-bit and all i need is to force it to be 64 bit with movabs instruction.
This code is assembling and working (access to var1 from internal function func1 and from external C program via dlsym()):
.section .data
.globl var1
var1:
.quad 0x012345
.section .text
.globl func1
func1:
movabs var1, %rax # if one is symbol, other must be %rax
inc %rax
movabs %rax, var1
ret
But i'm in doubt about Global Offset Table. Must i use it, or this "direct" access is absolutely correct?