I'm debuging a chromium with a modified boringssl.It always got a SegmentFault.
I found the problem is
EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
Disassembled code:
callq EC_KEY_get0_group
mov %eax,%edi
callq EC_GROUP_get_curve_name
The return type of EC_KEY_get0_group is a EC_GROUP* pointer,but it was passed to EC_GROUP_get_curve_name by a 32bit register.
The pointer was truncated and it caused the SegmentFault. Why compiler generates code like this?
Is there any compiler option to avoid this?
I can offer guidance to track down the issue, but not a specific answer to your question since I don't have the modified version of BoringSSL being used.
If you don't have prototypes for the C function then all the parameters and return values will default to an int type. The function will be treated as if there are an unspecified number of parameters.
The first thing that stood out to me was the mov $0, %al before each function call. This suggested to me that these functions are either variadic or prototypeless. The AMD64 System V ABI used by 64-bit Linux describes the AL register this way:
For calls that may call functions that use varargs or stdargs (prototype-less
calls or calls to functions containing ellipsis (. . . ) in the declaration) %al is used
as hidden argument to specify the number of vector registers used.
We can rule out them being variadic since the prototypes for them are supposed to be something like:
int EC_GROUP_get_curve_name(const EC_GROUP *group);
const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key);
Since these functions aren't variadic (don't use ...) then it is likely something in your code that isn't making the prototypes for these functions available.
We can see this same behaviour with these simple C function call:
testfunc.c:
#include <stdlib.h>
typedef struct ec_group_st EC_GROUP;
typedef struct ec_key_st EC_KEY;
int EC_GROUP_get_curve_name(const EC_GROUP *group);
const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key);
int testfun()
{
EC_KEY *ec = NULL;
return EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
}
If I use GCC to compile with gcc -Wall -Wextra -c -O3 testfunc.c -o testfunc.o and use objdump -D testfunc.o to look at the generated code it looks like:
0000000000000000 <testfun>:
0: 48 83 ec 08 sub $0x8,%rsp
4: 31 ff xor %edi,%edi
6: e8 00 00 00 00 callq b <testfun+0xb>
b: 48 83 c4 08 add $0x8,%rsp
f: 48 89 c7 mov %rax,%rdi
12: e9 00 00 00 00 jmpq 17 <testfun+0x17>
The code above seems correct as the 64-bit return value (pointer in RAX) from the first function call is passed to the second function call as expected. The code doesn't set AL to zero either.
If however I take the same code and comment out the prototypes for the functions like this:
#include <stdlib.h>
typedef struct ec_group_st EC_GROUP;
typedef struct ec_key_st EC_KEY;
/*int EC_GROUP_get_curve_name(const EC_GROUP *group);
const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key);*/
int testfun()
{
EC_KEY *ec = NULL;
return EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
}
I get this generated code:
0000000000000000 <testfun>:
0: 48 83 ec 08 sub $0x8,%rsp
4: 31 ff xor %edi,%edi
6: 31 c0 xor %eax,%eax
8: e8 00 00 00 00 callq d <testfun+0xd>
d: 48 83 c4 08 add $0x8,%rsp
11: 89 c7 mov %eax,%edi
13: 31 c0 xor %eax,%eax
15: e9 00 00 00 00 jmpq 1a <testfun+0x1a>
Now we have RAX(AL being the lower 8 bits of RAX) being set to zero and the return value from the first function call is being treated as a 32-bit int which is similar to the behaviour you are seeing. I recommend at least building your C files with -Wall -Wextra to see a wider variety of warnings. In the case of the code without prototypes my compiler threw these warnings:
testfunc.c: In function ‘testfun’:
testfunc.c:12:12: warning: implicit declaration of function ‘EC_GROUP_get_curve_name’ [-Wimplicit-function-declaratio
]
return EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
^~~~~~~~~~~~~~~~~~~~~~~
testfunc.c:12:36: warning: implicit declaration of function ‘EC_KEY_get0_group’ [-Wimplicit-function-declaration]
return EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
^~~~~~~~~~~~~~~~~
I would look for similar kinds of warning about implicit declarations in your build output and verify in your code that the function prototypes have been properly included.
I have a function defined in assembly that is calling a libc function (swapcontext). I invoke that function from my C code. For the purpose of creating a reproducible example, I'm using 'puts' instead:
foo.S:
.globl foo
foo:
call puts
ret
test.c:
void foo(char *str);
int main() {
foo("Hello World\n");
return 0;
}
Compile:
gcc test.c foo.S -o test
This compiles fine. Dis-assembling the result binary however shows that a valid call instruction wasn't inserted by the linker:
objdump -dR:
0000000000000671 <foo>:
671: e8 00 00 00 00 callq 676 <foo+0x5>
672: R_X86_64_PC32 puts#GLIBC_2.2.5-0x4
676: c3 retq
677: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
67e: 00 00
0000000000000530 <puts#plt>:
530: ff 25 9a 0a 20 00 jmpq *0x200a9a(%rip) # 200fd0 <puts#GLIBC_2.2.5>
536: 68 00 00 00 00 pushq $0x0
53b: e9 e0 ff ff ff jmpq 520 <.plt>
Execution:
./test1: Symbol `puts' causes overflow in R_X86_64_PC32 relocation
Segmentation fault
Any ideas why?
For your updated totally separate question, which replaced your question about disassembling a .o:
semi-related: Unexpected value of a function pointer local variable mentions the fact that the linker transforms references to puts to puts#plt for you in a non-PIE (because that lets you get efficient code if statically linking), but not in a PIE.
libc gets mapped more than 2GiB away from the main executable so a call rel32 can't reach it.
See also Can't call C standard library function on 64-bit Linux from assembly (yasm) code, which shows AT&T and NASM syntax for calling libc functions from a PIE executable, either via the PLT call puts#plt or gcc -fno-plt style with call *puts#gotpcrel(%rip).
You appear to be disassembling an object file with relocations.
Relocations are stubs for the linker to resolve when the file is loaded.
To properly view the relocations and symbol names, use objdump -dr test or objdump -dR test.
The output will be similar to this:
0000000000000000 <foo>:
0: e8 00 00 00 00 callq 5 <foo+0x5>
1: R_X86_64_PLT32 swapcontext-0x4
You may also consider adding a ret instruction at the end of foo, just in case swapcontext errors.
As shown by your objdump -dR output, both of these refer to libc functions:
670: R_X86_64_PC32 swapcontext#GLIBC_2.2.5-0x4
# 200fd0 <swapcontext#GLIBC_2.2.5>
I am trying to convert my .c file to a .s file using TCC, however, I get the error: tcc: cannot specify multiple files with -c
tcc.exe main.c -c main.S
What should I do?
tcc, as far as I can tell, does not have an option to generate an assembly listing.
tcc -c foo.c takes the C source file foo.c as input and generates a binary object file foo.o.
It can also take assembly files as input:
tcc -c asm.S preprocesses and assembles the assembly source in the existing asm.S file and generates an object file asm.o.
tcc -c asm.s is similar, but it doesn't preprocess the input file before assembling it.
The man page says:
TCC options are a very much like gcc options. The main difference is
that TCC can also execute directly the resulting program and give it
runtime arguments.
If tcc had an option to generate an assembly listing, then surely it would use the same option that gcc (and many other Unix-based compilers) use, namely -S -- but:
$ tcc -S foo.c
tcc: error: invalid option -- '-S'
$
You can get an assembly listing of sorts using objdump:
$ cat foo.c
#include <stdio.h>
int main(void) {
puts("hello");
}
$ tcc -c foo.c
$ objdump -d foo.o
foo.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 81 ec 00 00 00 00 sub $0x0,%rsp
b: 48 8d 05 fc ff ff ff lea -0x4(%rip),%rax # e <main+0xe>
12: 48 89 c7 mov %rax,%rdi
15: b8 00 00 00 00 mov $0x0,%eax
1a: e8 fc ff ff ff callq 1b <main+0x1b>
1f: c9 leaveq
20: c3 retq
$
but as you can see you lose some information that you'd get from a compiler-generated assembly listing. (Playing with objdump options might give you more information.)
I'm using tcc version 0.9.25 on a Linux x86_64 system.
(remyabel posted a similar but less detailed answer but deleted it, I'm not sure why.)
I'm implementing a genetic algorithm, the creatures are functions that have three pointers as input and output.
All have the form:
// No need for global variables
void _start (float *i, float *o, float *m)
{
...
...
...
}
The creatures should be a few thousand, and very small, so I decided not to use shared objects but simply load raw code and run it.
The creatures are compiled
gcc -O3 -c code.c
then I take the code of the function in this way
objcopy -O binary --only-section=.text code.o rawcode
and then load the code into memory and run it
((void(*)(void*,void*,void*)) loaded_code) (i, o, m);
This work until in the source code there aren't floating-point literals, for example the code:
void _start (int *i, int *o, int *m)
{
i[0] = m[0] + m[1];
}
Compilated produces this working code:
gcc -O3 -c code.c
objdump -d code.o
code.o: formato del file elf64-x86-64
Disassemblamento della sezione .text:
0000000000000000 <_start>:
0: f3 0f 10 02 movss (%rdx),%xmm0
4: f3 0f 58 42 04 addss 0x4(%rdx),%xmm0
9: f3 0f 11 07 movss %xmm0,(%rdi)
d: c3 retq
But a function with floating-point literal as:
void _start (float *i, float *o, float *m)
{
i[0] = m[0] + 3.0f;
}
Produces a code that when executed doesn't give the correct result
gcc -O3 -c code.c
objdump -d code.o
code.o: formato del file elf64-x86-64
Disassemblamento della sezione .text:
0000000000000000 <_start>:
0: f3 0f 10 05 00 00 00 movss 0x0(%rip),%xmm0 # 8 <_start+0x8>
7: 00
8: f3 0f 58 02 addss (%rdx),%xmm0
c: f3 0f 11 07 movss %xmm0,(%rdi)
10: c3 retq
And this happens every time that a instruction is generated using %rip.
How do I setting gcc to not generate this code? In theory, to insert a floating-point constant can be done as here or not?
You have any suggestion to avoid this problem?
The compiler puts the constants into the .rodata section which you don't even copy, so it isn't just a relocation problem. You could use a custom linker script that merges and relocates the code as necessary instead of objcopy, as follows:
OUTPUT_FORMAT(binary)
SECTIONS
{
merged : {
*(.text)
*(.rodata)
} = 0x90
/DISCARD/ : {
*(*) /* discard everything else */
}
}
Not sure why you wanted to avoid shared objects, that would be the simplest solution. You could just dlopen them and don't bother with the details.
I was wondering how to use GCC on my C source file to dump a mnemonic version of the machine code so I could see what my code was being compiled into. You can do this with Java but I haven't been able to find a way with GCC.
I am trying to re-write a C method in assembly and seeing how GCC does it would be a big help.
If you compile with debug symbols (add -g to your GCC command line, even if you're also using -O31),
you can use objdump -S to produce a more readable disassembly interleaved with C source.
>objdump --help
[...]
-S, --source Intermix source code with disassembly
-l, --line-numbers Include line numbers and filenames in output
objdump -drwC -Mintel is nice:
-r shows symbol names on relocations (so you'd see puts in the call instruction below)
-R shows dynamic-linking relocations / symbol names (useful on shared libraries)
-C demangles C++ symbol names
-w is "wide" mode: it doesn't line-wrap the machine-code bytes
-Mintel: use GAS/binutils MASM-like .intel_syntax noprefix syntax instead of AT&T
-S: interleave source lines with disassembly.
You could put something like alias disas="objdump -drwCS -Mintel" in your ~/.bashrc. If not on x86, or if you like AT&T syntax, omit -Mintel.
Example:
> gcc -g -c test.c
> objdump -d -M intel -S test.o
test.o: file format elf32-i386
Disassembly of section .text:
00000000 <main>:
#include <stdio.h>
int main(void)
{
0: 55 push ebp
1: 89 e5 mov ebp,esp
3: 83 e4 f0 and esp,0xfffffff0
6: 83 ec 10 sub esp,0x10
puts("test");
9: c7 04 24 00 00 00 00 mov DWORD PTR [esp],0x0
10: e8 fc ff ff ff call 11 <main+0x11>
return 0;
15: b8 00 00 00 00 mov eax,0x0
}
1a: c9 leave
1b: c3 ret
Note that this isn't using -r so the call rel32=-4 isn't annotated with the puts symbol name. And looks like a broken call that jumps into the middle of the call instruction in main. Remember that the rel32 displacement in the call encoding is just a placeholder until the linker fills in a real offset (to a PLT stub in this case, unless you statically link libc).
Footnote 1: Interleaving source can be messy and not very helpful in optimized builds; for that, consider https://godbolt.org/ or other ways of visualizing which instructions go with which source lines. In optimized code there's not always a single source line that accounts for an instruction but the debug info will pick one source line for each asm instruction.
If you give GCC the flag -fverbose-asm, it will
Put extra commentary information in the generated assembly code to make it more readable.
[...] The added comments include:
information on the compiler version and command-line options,
the source code lines associated with the assembly instructions, in the form FILENAME:LINENUMBER:CONTENT OF LINE,
hints on which high-level expressions correspond to the various assembly instruction operands.
Use the -S (note: capital S) switch to GCC, and it will emit the assembly code to a file with a .s extension. For example, the following command:
gcc -O2 -S foo.c
will leave the generated assembly code on the file foo.s.
Ripped straight from http://www.delorie.com/djgpp/v2faq/faq8_20.html (but removing erroneous -c)
Using the -S switch to GCC on x86 based systems produces a dump of AT&T syntax, by default, which can be specified with the -masm=att switch, like so:
gcc -S -masm=att code.c
Whereas if you'd like to produce a dump in Intel syntax, you could use the -masm=intel switch, like so:
gcc -S -masm=intel code.c
(Both produce dumps of code.c into their various syntax, into the file code.s respectively)
In order to produce similar effects with objdump, you'd want to use the --disassembler-options= intel/att switch, an example (with code dumps to illustrate the differences in syntax):
$ objdump -d --disassembler-options=att code.c
080483c4 <main>:
80483c4: 8d 4c 24 04 lea 0x4(%esp),%ecx
80483c8: 83 e4 f0 and $0xfffffff0,%esp
80483cb: ff 71 fc pushl -0x4(%ecx)
80483ce: 55 push %ebp
80483cf: 89 e5 mov %esp,%ebp
80483d1: 51 push %ecx
80483d2: 83 ec 04 sub $0x4,%esp
80483d5: c7 04 24 b0 84 04 08 movl $0x80484b0,(%esp)
80483dc: e8 13 ff ff ff call 80482f4 <puts#plt>
80483e1: b8 00 00 00 00 mov $0x0,%eax
80483e6: 83 c4 04 add $0x4,%esp
80483e9: 59 pop %ecx
80483ea: 5d pop %ebp
80483eb: 8d 61 fc lea -0x4(%ecx),%esp
80483ee: c3 ret
80483ef: 90 nop
and
$ objdump -d --disassembler-options=intel code.c
080483c4 <main>:
80483c4: 8d 4c 24 04 lea ecx,[esp+0x4]
80483c8: 83 e4 f0 and esp,0xfffffff0
80483cb: ff 71 fc push DWORD PTR [ecx-0x4]
80483ce: 55 push ebp
80483cf: 89 e5 mov ebp,esp
80483d1: 51 push ecx
80483d2: 83 ec 04 sub esp,0x4
80483d5: c7 04 24 b0 84 04 08 mov DWORD PTR [esp],0x80484b0
80483dc: e8 13 ff ff ff call 80482f4 <puts#plt>
80483e1: b8 00 00 00 00 mov eax,0x0
80483e6: 83 c4 04 add esp,0x4
80483e9: 59 pop ecx
80483ea: 5d pop ebp
80483eb: 8d 61 fc lea esp,[ecx-0x4]
80483ee: c3 ret
80483ef: 90 nop
godbolt is a very useful tool, they list only has C++ compilers but you can use -x c flag in order to get it treat the code as C. It will then generate an assembly listing for your code side by side and you can use the Colourise option to generate colored bars to visually indicate which source code maps to the generated assembly. For example the following code:
#include <stdio.h>
void func()
{
printf( "hello world\n" ) ;
}
using the following command line:
-x c -std=c99 -O3
and Colourise would generate the following:
Did you try gcc -S -fverbose-asm -O source.c then look into the generated source.s assembler file ?
The generated assembler code goes into source.s (you could override that with -o assembler-filename ); the -fverbose-asm option asks the compiler to emit some assembler comments "explaining" the generated assembler code. The -O option asks the compiler to optimize a bit (it could optimize more with -O2 or -O3).
If you want to understand what gcc is doing try passing -fdump-tree-all but be cautious: you'll get hundreds of dump files.
BTW, GCC is extensible thru plugins or with MELT (a high level domain specific language to extend GCC; which I abandoned in 2017)
You can use gdb for this like objdump.
This excerpt is taken from http://sources.redhat.com/gdb/current/onlinedocs/gdb_9.html#SEC64
Here is an example showing mixed source+assembly for Intel x86:
(gdb) disas /m main
Dump of assembler code for function main:
5 {
0x08048330 : push %ebp
0x08048331 : mov %esp,%ebp
0x08048333 : sub $0x8,%esp
0x08048336 : and $0xfffffff0,%esp
0x08048339 : sub $0x10,%esp
6 printf ("Hello.\n");
0x0804833c : movl $0x8048440,(%esp)
0x08048343 : call 0x8048284
7 return 0;
8 }
0x08048348 : mov $0x0,%eax
0x0804834d : leave
0x0804834e : ret
End of assembler dump.
Use the -S (note: capital S) switch to GCC, and it will emit the assembly code to a file with a .s extension. For example, the following command:
gcc -O2 -S -c foo.c
I haven't given a shot to gcc, but in case of g++, the command below works for me.
-g for debug build
-Wa,-adhln are passed to assembler for listing with source code
g++ -g -Wa,-adhln src.cpp
For risc-v dissasembly, these flags are nice:
riscv64-unknown-elf-objdump -d -S -l --visualize-jumps --disassembler-color=color --inlines
-d: disassemble, most basic flag
-S: intermix source. Note: must use -g flag while compiling
-l: line numbers
--visualize-jumps: fancy arrows, not too useful but why not. Sometimes get's too messy and actually makes reading the source harder. Taken from Peter Cordes's comment: --visualize-jumps=coloris also an option, to use different colors for different arrows
--disassembler-color=color: give the disassembly some color
--inlines: print out inlines
Maybe usefull:
-M numeric: Use numeric reg names instead of abi names, useful if you are doing cpu dev and don't know the abi names by heart
-M no-aliases: don't use psudoinstructions like li and call
Example:
main.o:
#include <stdio.h>
#include <stdint.h>
static inline void example_inline(const char* str) {
for (int i = 0; str[i] != 0; i++)
putchar(str[i]);
}
int main() {
printf("Hello world");
example_inline("Hello! I am inlined");
return 0;
}
I recommend to use -O0 if you want intermix sources. Intermix sources becomes very messy if using -O2.
Command:
riscv64-unknown-elf-gcc main.c -c -O0 -g
riscv64-unknown-elf-objdump -d -S -l --disassembler-color=color --inlines main.o
Dissasembly:
main.o: file format elf64-littleriscv
Disassembly of section .text:
0000000000000000 <example_inline>:
example_inline():
/Users/cyao/test/main.c:4
#include <stdio.h>
#include <stdint.h>
static inline void example_inline(const char* str) {
0: 7179 addi sp,sp,-48
2: f406 sd ra,40(sp)
4: f022 sd s0,32(sp)
6: 1800 addi s0,sp,48
8: fca43c23 sd a0,-40(s0)
000000000000000c <.LBB2>:
/Users/cyao/test/main.c:5
for (int i = 0; str[i] != 0; i++)
c: fe042623 sw zero,-20(s0)
10: a01d j 36 <.L2>
0000000000000012 <.L3>:
/Users/cyao/test/main.c:6 (discriminator 3)
putchar(str[i]);
12: fec42783 lw a5,-20(s0)
16: fd843703 ld a4,-40(s0)
1a: 97ba add a5,a5,a4
1c: 0007c783 lbu a5,0(a5)
20: 2781 sext.w a5,a5
22: 853e mv a0,a5
24: 00000097 auipc ra,0x0
28: 000080e7 jalr ra # 24 <.L3+0x12>
/Users/cyao/test/main.c:5 (discriminator 3)
for (int i = 0; str[i] != 0; i++)
2c: fec42783 lw a5,-20(s0)
30: 2785 addiw a5,a5,1
32: fef42623 sw a5,-20(s0)
0000000000000036 <.L2>:
/Users/cyao/test/main.c:5 (discriminator 1)
36: fec42783 lw a5,-20(s0)
3a: fd843703 ld a4,-40(s0)
3e: 97ba add a5,a5,a4
40: 0007c783 lbu a5,0(a5)
44: f7f9 bnez a5,12 <.L3>
0000000000000046 <.LBE2>:
/Users/cyao/test/main.c:7
}
46: 0001 nop
48: 0001 nop
4a: 70a2 ld ra,40(sp)
4c: 7402 ld s0,32(sp)
4e: 6145 addi sp,sp,48
50: 8082 ret
0000000000000052 <main>:
main():
/Users/cyao/test/main.c:9
int main() {
52: 1141 addi sp,sp,-16
54: e406 sd ra,8(sp)
56: e022 sd s0,0(sp)
58: 0800 addi s0,sp,16
/Users/cyao/test/main.c:10
printf("Hello world");
5a: 000007b7 lui a5,0x0
5e: 00078513 mv a0,a5
62: 00000097 auipc ra,0x0
66: 000080e7 jalr ra # 62 <main+0x10>
/Users/cyao/test/main.c:11
example_inline("Hello! I am inlined");
6a: 000007b7 lui a5,0x0
6e: 00078513 mv a0,a5
72: 00000097 auipc ra,0x0
76: 000080e7 jalr ra # 72 <main+0x20>
/Users/cyao/test/main.c:13
return 0;
7a: 4781 li a5,0
/Users/cyao/test/main.c:14
}
7c: 853e mv a0,a5
7e: 60a2 ld ra,8(sp)
80: 6402 ld s0,0(sp)
82: 0141 addi sp,sp,16
84: 8082 ret
PS. There are colors in the dissembled code
use -Wa,-adhln as option on gcc or g++ to produce a listing output to stdout.
-Wa,... is for command line options for the assembler part (execute in gcc/g++ after C/++ compilation). It invokes as internally (as.exe in Windows).
See
>as --help
as command line to see more help for the assembler tool inside gcc