Why does GCC not add .section into the assembly - c

If you look at the second line of this program it just says ".text". When I write assembly programs I though that you had to put ".section .text" Why does GCC omit the ".section". I also noticed that it includes it before declaring rodata bellow ".section .rodata".
Also just wondering what ".type sum, #function" does? I wrote an assembly function this morning without it and it executed fine.
.file "test.c"
.text
.globl sum
.type sum, #function
sum:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movss %xmm0, -4(%rbp)
movss %xmm1, -8(%rbp)
movss -4(%rbp), %xmm0
mulss -8(%rbp), %xmm0
cvttss2si %xmm0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size sum, .-sum
.section .rodata
.LC2:
.string "%d\n"
.text
.globl main
.type main, #function
main:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movss .LC0(%rip), %xmm1
movss .LC1(%rip), %xmm0
call sum
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC2, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size main, .-main
.section .rodata
.align 4
.LC0:
.long 1092930765
.align 4
.LC1:
.long 1092825907
.ident "GCC: (Ubuntu 4.9.2-10ubuntu13) 4.9.2"
.section .note.GNU-stack,"",#progbits

Collecting up some comments into an answer:
Before arbitrary section names were possible, .text, .data, and .bss were assembler directives. Now, you can write .section .text instead. This should all be documented in the GNU as manual. (linked to latest version).
.type sum, #function
sets some ELF symbol-type stuff. IDK if this matters for dynamic linking, but it doesn't for static linkage. There's a lot of stuff the compiler emits but that you don't actually need for your code to run. This is not a bad thing.
For the other things in gcc asm output, have a look at my answer to GCC Assembly Optimizations - Why are these equivalent?

Related

Does necessary content of same header will be duplicated in produced executable?

I use gcc. We know the cpp expands all macros definitions and include statements and passes the result to the actual compiler to create an executable file. I tested the result of cpp and see that some parts of header which are necessary, are included in output of cpp for each source file.
But I want to know if in a project I have a header that is included in multiple source files, then does the related content to that header will be duplicated multiple times in produced executable? Or there will be multiple shortcuts to them? If there will be shortcuts, I want to know why cpp replaces shortcuts of source files with more code and pass the result to cc1?
For example in a header, I have a function with name kids
int kids(){
return 1;
}
and call it in test.c source file. The cpp puts the definition of kids in its output. But in compiled file (test.s which is the result of cc -S test.c), I only see call kids which is replaced instead of function definition. I call that a shortcut.I want to know what will happen for that function and its calls in executable?
Edit:
The assembly off test.c is:
.file "test.c"
.text
.globl kids
.type kids, #function
kids:
.LFB0:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $1, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size kids, .-kids
.section .rodata
.LC0:
.string "C Rocks + Ali!"
.LC1:
.string "%d"
.text
.globl main
.type main, #function
main:
.LFB1:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
leaq .LC0(%rip), %rdi
call puts#PLT
movl $0, %eax
call kids
movl %eax, %esi
leaq .LC1(%rip), %rdi
movl $0, %eax
call printf#PLT
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size main, .-main
.ident "GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0"
.section .note.GNU-stack,"",#progbits
.section .note.gnu.property,"a"
.align 8
.long 1f - 0f
.long 4f - 1f
.long 5
0:
.string "GNU"
1:
.align 8
.long 0xc0000002
.long 3f - 2f
2:
.long 0x3
3:
.align 8
4:

Error: operand size mismatch for `lea' (seems like syntax error)

I'm trying to add a function S_0x804853E in an assembly file compiled by GCC. And i'm trying to assemble the file to execuable file. The complete assembly file is followed.
.file "simple.c"
.intel_syntax noprefix
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
push ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
mov ebp, esp
.cfi_def_cfa_register 5
sub esp, 16
call __x86.get_pc_thunk.ax
add eax, OFFSET FLAT:_GLOBAL_OFFSET_TABLE_
mov DWORD PTR -4[ebp], 3
mov eax, 0
leave
call S_0x804853E # note that this line is manually added.
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size main, .-main
.section .text.__x86.get_pc_thunk.ax,"axG",#progbits,__x86.get_pc_thunk.ax,comdat
.globl __x86.get_pc_thunk.ax
.hidden __x86.get_pc_thunk.ax
.type __x86.get_pc_thunk.ax, #function
__x86.get_pc_thunk.ax:
.LFB1:
.cfi_startproc
mov eax, DWORD PTR [esp]
ret
.cfi_endproc
.LFE1:
.ident "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0"
.section .note.GNU-stack,"",#progbits
# note that codes below are manually added.
.type S_0x804853E, #function
S_0x804853E:
push ebp
mov esp,ebp
push ebx
sub $0x4,esp
call S_0x80485BB
add $_GLOBAL_OFFSET_TABLE_,eax
sub $0xC,esp
lea S_0x80486B8,edx
push edx
mov eax,ebx
call puts
add $0x10,esp
nop
mov -0x4(ebp),ebx
leave
ret
.type S_0x80485BB, #function
S_0x80485BB:
mov (esp),eax
ret
.section .rodata
S_0x80486B8:
.byte 0x36
.byte 0x00
I'm using commands below to assemble. And Errors followed.
$ gcc -m32 -no-pie -nostartfiles simple.s -o simple
simple.s: Assembler messages:
simple.s:49: Error: operand size mismatch for `lea'
simple.s:55: Error: junk `(ebp)' after expression
I'm not very familiar with assembly. Apologize if the problem can be easily solved by google. But i failed to find any related explanations. Thanks for your help.
The main problem is that i mixed up the grammar of intel and AT&T. The codes generated from the tool are AT&T without operator suffix('b','l','w','q').
Compiling C code to AT&T and making up the operator suffix make sense. edited codes followed.
.file "simple.c"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $16, %esp
call __x86.get_pc_thunk.ax
addl $_GLOBAL_OFFSET_TABLE_, %eax
movl $3, -4(%ebp)
movl $0, %eax
leave
call S_0x804853E # note that this line is mannally added
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size main, .-main
.section .text.__x86.get_pc_thunk.ax,"axG",#progbits,__x86.get_pc_thunk.ax,comdat
.globl __x86.get_pc_thunk.ax
.hidden __x86.get_pc_thunk.ax
.type __x86.get_pc_thunk.ax, #function
__x86.get_pc_thunk.ax:
.LFB1:
.cfi_startproc
movl (%esp), %eax
ret
.cfi_endproc
# note that codes below are mannally added
.type S_0x804853E, #function
S_0x804853E:
pushl %ebp
movl %esp,%ebp
pushl %ebx
subl $0x4,%esp
call S_0x80485BB
addl $_GLOBAL_OFFSET_TABLE_,%eax
subl $0xC,%esp
lea S_0x80486B8,%edx
pushl %edx
movl %eax,%ebx
call puts
addl $0x10,%esp
nop
movl -0x4(%ebp),%ebx
leave
ret
.type S_0x80485BB, #function
S_0x80485BB:
movl (%esp),%eax
ret
.section .rodata
S_0x80486B8:
.byte 0x36
.byte 0x00
Codes can be assembled by gcc without warnings and errors.
-------------------------split line for new edit----------------------
Thanks for help from #Peter Cordes.
It's unnecessary to explictly give all instructions the operand-size suffix. We use suffix only if the operand size of the instuction seems ambiguous without the declaration of size.
EX:neither operand is a register.
movl $4, -4(%ebp)

Variable to return or return directly?

I'm learning to program and sometimes I find that using a variable to return makes my code more readable.
I was wondering if these functions perform the same operations and are equally efficient.
CASE 1:
int Foo1()
{
int x = 5 + 6 + 7; // Return variable
return x;
}
int Foo2(int y)
{
return 5 + 6 + 7;
}
In this case I think that the initialization and sum occur at compile time so there's no difference between them.
CASE 2:
int Foo1(int y)
{
int x = y + 6 + 7; // Return variable
return x;
}
int Foo2(int y)
{
return y + 6 + 7;
}
But, what happen in this case? It seems that the initialization occur at execution time and it has to perform it.
Is returning the value directly faster than initialize a variable and then returning it? Should I always try to return values directly instead using a variable to return?
You can easily try this yourself.
You can get the assembly from your compiler
Without optimization:
(gcc -S -O0 -o src.S src.c)
.file "so_temp.c"
.text
.globl case1Foo1
.type case1Foo1, #function
case1Foo1:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $18, -4(%rbp)
movl -4(%rbp), %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size case1Foo1, .-case1Foo1
.globl case1Foo2
.type case1Foo2, #function
case1Foo2:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $18, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size case1Foo2, .-case1Foo2
.globl case2Foo1
.type case2Foo1, #function
case2Foo1:
.LFB2:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -20(%rbp)
movl -20(%rbp), %eax
addl $13, %eax
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE2:
.size case2Foo1, .-case2Foo1
.globl case2Foo2
.type case2Foo2, #function
case2Foo2:
.LFB3:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
movl -4(%rbp), %eax
addl $13, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE3:
.size case2Foo2, .-case2Foo2
.ident "GCC: (Ubuntu 8.3.0-6ubuntu1) 8.3.0"
.section .note.GNU-stack,"",#progbits
Ther you can see, that the foo2 versions have a few instructions less than the foo1 versions of the functions.
With optimization turned to O3:
(gcc -S -O3 -o src.S src.c)
.file "so_temp.c"
.text
.p2align 4,,15
.globl case1Foo1
.type case1Foo1, #function
case1Foo1:
.LFB0:
.cfi_startproc
movl $18, %eax
ret
.cfi_endproc
.LFE0:
.size case1Foo1, .-case1Foo1
.p2align 4,,15
.globl case1Foo2
.type case1Foo2, #function
case1Foo2:
.LFB5:
.cfi_startproc
movl $18, %eax
ret
.cfi_endproc
.LFE5:
.size case1Foo2, .-case1Foo2
.p2align 4,,15
.globl case2Foo1
.type case2Foo1, #function
case2Foo1:
.LFB2:
.cfi_startproc
leal 13(%rdi), %eax
ret
.cfi_endproc
.LFE2:
.size case2Foo1, .-case2Foo1
.p2align 4,,15
.globl case2Foo2
.type case2Foo2, #function
case2Foo2:
.LFB7:
.cfi_startproc
leal 13(%rdi), %eax
ret
.cfi_endproc
.LFE7:
.size case2Foo2, .-case2Foo2
.ident "GCC: (Ubuntu 8.3.0-6ubuntu1) 8.3.0"
.section .note.GNU-stack,"",#progbits
both versions are exactly the same.
Still I don't think that this is something you should optimize yourself.
In this case readable code should be preferred, especially as code normally isn't compiled with optimizations turned off.
Case 2 is more efficient, but is often not needed as the compiler is extremely likely to optimize case 1 into case 2.
Go for readability if it doesn't hurt performance (as in this case).
Any compiler of at least modest quality will, at even low levels of optimization (such as GCC’s -O1), compile these to the same code. For the most part, any correct optimization you can easily see will be performed by a good compiler.
The C standard does not require compilers to mindlessly compile code into instructions that perform the exact steps in the C source code. It only requires compilers to produce code that has the same effects. Those effects are defined in terms of observable behavior, which includes the output of the program, interactions with the user, and access to volatile objects (special objects you will learn about later). Compilers will eliminate things like intermediate variables as long as they can do so without changing the observable behavior.

Putting a local array changes assembly output for X86-64

When we have just an int variable in main:
int main() {
int d;
return 0;
}
Following code is generated for x86-64 on Linux by gcc -S test.c.
.file "test.c"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 6.3.1 20170109"
.section .note.GNU-stack,"",#progbits
Putting an array as local variable
int main() {
int d[2];
return 0;
}
generates a lot of extraneous code at the beginning which I am not able to comprehend.
.file "test.c"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
leaq -4144(%rsp), %rsp
orq $0, (%rsp)
leaq 4128(%rsp), %rsp
movq %fs:40, %rax
movq %rax, -8(%rbp)
xorl %eax, %eax
movl $0, %eax
movq -8(%rbp), %rdx
xorq %fs:40, %rdx
je .L3
call __stack_chk_fail#PLT
.L3:
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 6.3.1 20170109"
.section .note.GNU-stack,"",#progbits
Specifically, what are these instructions doing?
leaq -4144(%rsp), %rsp
orq $0, (%rsp)
leaq 4128(%rsp), %rsp
movq %fs:40, %rax
movq %rax, -8(%rbp)
xorl %eax, %eax
movl $0, %eax

Incrementing a variable through embedded assembly language

I am trying to understand how to embed assembly language in C (using gcc on x86_64 architecture). I wrote this program to increment the value of a single variable. But I am getting garbage value as output. And ideas why?
#include <stdio.h>
int main(void) {
int x;
x = 4;
asm("incl %0": "=r"(x): "r0"(x));
printf("%d", x);
return 0;
}
Thanks
Update The program is giving expected result on gcc 4.8.3 but not on gcc 4.6.3. I am pasting the assembly output of the non-working code:
.file "abc.c"
.section .rodata
.LC0:
.string "%d"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
pushq %rbx
subq $24, %rsp
movl $4, -20(%rbp)
movl -20(%rbp), %eax
incl %edx
movl %edx, %ebx
.cfi_offset 3, -24
movl %ebx, -20(%rbp)
movl $.LC0, %eax
movl -20(%rbp), %edx
movl %edx, %esi
movq %rax, %rdi
movl $0, %eax
call printf
movl $0, %eax
addq $24, %rsp
popq %rbx
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section .note.GNU-stack,"",#progbits
You don't need to say x twice; once is sufficient:
asm("incl %0": "+r"(x));
The +r says that the value will be input and output.
Your way, with separate inputs and output registers, requires that you take the input from %1, add one, and write the output to %0, but you can't do that with incl.
The reason it works on some compilers is because GCC is free to allocate both %0 and %1 to the same register, and appears to have done so in those cases, but it does not have to. Incidentally, if you want to prevent GCC allocating an input and output to the same register (say, if you want to initialize the output before using the input to calculate a final output), you need to use the & modifier.
The documentation for the modifiers is here.

Resources