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:
Related
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)
I am trying to find the issue with below code, need to know how linker is able to track global variable multiple definition issue in below program, I am not sure much on how linker internally performs checking so requesting help to clarify.
**hello.h**
#ifndef __HELLO_
#define __HELLO_
static int s = 20;
int g = 10;
#endif
**cat hello1.c**
#include <stdio.h>
#include "hello.h"
//int g = 10;
int main()
{
g++;
s++;
printf("g : %d s : %d\n", g, s);
function();
return 0;
}
**cat hello2.c**
#include <stdio.h>
#include "hello.h"
//extern int g;
void function()
{
g++;
s++;
printf("g : %d s : %d\n", g, s);
}
**gcc -save-temps hello1.c hello2.c -o hello**
hello2.o:(.data+0x4): multiple definition of `g'
hello1.o:(.data+0x4): first defined here
**collect2: error: ld returned 1 exit status**
I don't need solution to fix this error, I know above program will throw multiple definition error of g as above but can anyone please explain how it tracks this error at linking stage?.
Here is the output of assembly code.
**cat hello1.s**
.file "hello1.c"
.data
.align 4
.type s, #object
.size s, 4
s:
.long 20
.globl g
.align 4
.type g, #object
.size g, 4
g:
.long 10
.section .rodata
.LC0:
.string "g : %d s : %d\n"
.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 g(%rip), %eax
addl $1, %eax
movl %eax, g(%rip)
movl s(%rip), %eax
addl $1, %eax
movl %eax, s(%rip)
movl s(%rip), %edx
movl g(%rip), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
call function
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
.section .note.GNU-stack,"",#progbits
**cat hello2.s**
.file "hello2.c"
.data
.align 4
.type s, #object
.size s, 4
s:
.long 20
.globl g
.align 4
.type g, #object
.size g, 4
g:
.long 10
.section .rodata
.LC0:
.string "g : %d s : %d\n"
.text
.globl function
.type function, #function
function:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl g(%rip), %eax
addl $1, %eax
movl %eax, g(%rip)
movl s(%rip), %eax
addl $1, %eax
movl %eax, s(%rip)
movl s(%rip), %edx
movl g(%rip), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size function, .-function
.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
.section .note.GNU-stack,"",#progbits
Please share me the reference if this query is already posted earlier, unable to track the similar link.
Internally compiler generates two distinct object files hello1.o and hello2.o. Each of them exports variable g:
$ readelf -sW hello1.o | grep GLOBAL
8: 0000000000000000 4 OBJECT GLOBAL DEFAULT 2 g
$ readelf -sW hello2.o | grep GLOBAL
10: 0000000000000000 4 OBJECT GLOBAL DEFAULT 2 g
Linker detects that there is more then one definition of g when building a global symbol table for the executable and reports an error.
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.
I am new here and I converted code from C language to asm. However, it doesn't look like normal code in asm language. So my question is how can I convert a code from C(or C++) language to Assembly language, that the converted asm code could be run on Emu8086.
Here is a simple c code:
#include<stdio.h>
void Hello(){
printf("Hello world");
}
int main (){
Hello();
return 0;
}
Then I converted it with gcc -S test.c and here is the answer:
.file "test1.c"
.section .rodata
.LC0:
.string "Hello world"
.text
.globl Hello
.type Hello, #function
Hello:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
leaq .LC0(%rip), %rdi
movl $0, %eax
call printf#PLT
nop
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size Hello, .-Hello
.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
movl $0, %eax
call Hello
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size main, .-main
.ident "GCC: (Debian 6.3.0-18+deb9u1) 6.3.0 20170516"
.section .note.GNU-stack,"",#progbits
Emu8086 does what it says on the tin: it emulates an Intel 8086 processor. The assembly that GCC has produced is for your host machine (since you haven't told it to do otherwise), which evidently uses an x86-64 instructions set. The 8086 can't understand most of these instructions. You need to cross-compile it to an x86 16-bit real-mode executable. The -m16 option on GCC will generate 16-bit code, but it apparently still uses 32-bit registers (EAX, etc.). So you will have to find a compiler that targets the basic 8086 instruction set.
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?