Error invalid instruction suffix for push

I am trying to study passing arguments into a function via stack in assembly. I am using fedora 20, a 64-bit system. when I try the following code, pushl %ebp popl %ebp I get the error, Error: in...

The error you’re getting comes out from a very simple fact : the push instruction in 32-bit mode accepts 16-bit and 32-bit immediates as arguments. However, the push instruction used in 64-bit mode accepts only 16-bit and 64-bit immediates. Since you’re clearly compiling your code as 64-bit, the assembler throws an error, since it cannot possibly encode such an instruction. Also, do keep in mind that you force the operand size yourself by adding the l suffix to the push instruction. Everything I just wrote here is exactly the same for pop, except that it accepts registers/memory, not immediates.

However, you also need to keep in mind the differences in the ABI between 32-bit and 64-bit Linux systems. The ABI specifies, among other things, how parameters are passed to functions, and how to call the kernel from user-mode applications. Your code is clearly written for 32-bit mode, seeing how it uses the stack for passing arguments and the (very) obsolete int $0x80 way of invoking syscalls. In order to learn about the 64-bit ABI, see this document.

Alternatively, you have the option of compiling 32-bit code on a 64-bit system. Such an executable will work if you have the necessary 32-bit runtime libraries installed on your 64-bit system. Most distributions allow you to do that in different ways. Your compiler, as, has the --32 switch for emitting 32-bit code.

I have been having issues with compiling a program. I am unsure what these mean and I would be grateful if anyone could help.

C:UsersJoshuaDocumentsGitHubZeus-TSO_depslibmpg123dct64_sse.S: Assembler
 messages:
C:UsersJoshuaDocumentsGitHubZeus-TSO_depslibmpg123dct64_sse.S:41: Error:
 invalid instruction suffix for `push'
C:UsersJoshuaDocumentsGitHubZeus-TSO_depslibmpg123dct64_sse.S:46: Error:
 invalid instruction suffix for `push'
C:UsersJoshuaDocumentsGitHubZeus-TSO_depslibmpg123dct64_sse.S:449: Error: invalid instruction suffix for `pop'
C:UsersJoshuaDocumentsGitHubZeus-TSO_depslibmpg123dct64_sse.S:451: Error: invalid instruction suffix for `pop'
_depslibmpg123CMakeFileslibmpg123_static.dirbuild.make:378: recipe for targe
t '_deps/libmpg123/CMakeFiles/libmpg123_static.dir/dct64_sse.S.obj' failed
mingw32-make[2]:  [_deps/libmpg123/CMakeFiles/libmpg123_static.dir/dct64_sse.
S.obj] Error 1
CMakeFilesMakefile2:225: recipe for target '_deps/libmpg123/CMakeFiles/libmpg12
3_static.dir/all' failed
mingw32-make[1]:  [_deps/libmpg123/CMakeFiles/libmpg123_static.dir/all] Error
 2
Makefile:74: recipe for target 'all' failed
mingw32-make:  [all] Error 2

asked Oct 13, 2013 at 15:05

Zeusking19-Code's user avatar

2

It appears that you are trying to build 32-bit assembly code with 64-bit assembler.

You have 2 options:

  1. Use 32-bit assembler, for example by utilizing --32 option;
  2. Change code by substituting 64-bit (extended) registers such as %rax, for example, instead of 32-bit registers such as %eax used with push/pop instructions.

Since the build system appears to be CMake, I’d refer you to this manual on how to configure the build for various Assembly dialects in CMake.

You could try:

set(CMAKE_ASM_FLAGS "--32")

but I haven’t tested it.

answered Oct 13, 2013 at 15:13

Alexander Shukaev's user avatar

4

@bmmajeed on GNU/Linux, tools are typically installed to some predefined locations (e.g. /usr/local/bin, /usr/local/lib…). Unlike Windows, there is no one specific subidr for each app/tool. All the binaries of all tools are put together, all the libs are put together, etc. As a result, it is very painful to manually install/uninstall all the files related to some tool. Unless you do it from a tarball and keep that around, to use diogratia’s trick.

At the same time, GNU/Linux distributions are known for having so-called «package managers» together with «repositories». A repository is a server containing thousands of pre-built tools. Unlike Windows, on Linux you don’t need to search each tool in the browser and then download and install it manually. On Linux, you use a package manager:

  • apt update: fetch the repository and update the local list of available packages.
  • apt search ghdl: search if a package named ghdl exists.
  • apt install ghdl: install ghdl for me.

Next time you do apt update and apt upgrade, it will automatically install a new version of GHDL (if available).

Moreover, the packages you get through the manager are guaranteed to work for your OS, because those were built specifically for the libraries and versions you have.

When you download a tarball for Linux, you have no guarantee about it working. In this case, we do generate pre-built tarballs for Ubuntu 20.04. However, if you used any othe Linux distribution, you might have issues. This is different from Windows, because there is one single officially supported Windows at a time, and there is very good backwards compatibility.

apt (or apt-get) is the default package manager on Debian/Ubuntu. On other distributions, managers are pacman, dnf, yum, etc. All of the are equivalent and serve the same purpose.

Therefore, installing GHDL from tarballs or building it from sources is only suggested in case the version available through the package manager is not enough. That might be because it is outdated or because it was built with some options that don’t fit your needs. In this specific case, it might be problematic if the GHDL installed through apt was built with openieee. However, that should be fixed as soon as they update to 1.0.0, which was released a month ago.

I’m new to the Linux so I want to get through the basic reasons of the stuff.

Please, do see some Youtube video or some introduction to the GNU/Linux file structure and how package managers are used. I’m sure you will find examples specific about Ubuntu which will be easy to follow. I did a very basic introduction above, but explaining it in deep is out of the scope of this project.

Last night I was trying to setup my i686-elf-gcc cross compiler. After spending like an hour trying to figure out what was wrong with my current installation (I had the binaries from the debian repository, which I had assumed would work but seemed to be broken for me) and eventually decided to compile it myself. When I was finally done, I tried compiling something and it worked just fine. However, after closing out of that shell and opening a new one it no longer worked properly and kept giving a variety of different errors. I figured out that I forgot to export some of my environment variables in my zshrc, but after fixing that (I think) it still seems broken. Here are the relevant files/errors:

Makefile:

Code:

CC = /home/nv/opt/cross/bin/i686-elf-gcc
AS = nasm
AFLAGS = -f elf32
CFLAGS = -c -std=gnu99 -ffreestanding -O -Wall -w -g -I ../../include
LD = /home/nv/opt/cross/bin/i686-elf-gcc
LDFLAGS = -T linker.ld -ffreestanding -O2 -nostdlib -gcc

TARGET = bin/infinity.bin

OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c) $(shell find ./src -name «*.c»)) $(patsubst %.asm, %.o, $(wildcard *.asm) $(shell find ./src -name «*.asm»))

all: $(TARGET)

$(TARGET): $(OBJECTS)
        $(LD) -r -o $@  $^

%.o: %.c
        $(CC) $(CFLAGS) $^ -o $@
%.o: %.asm
        $(AS) $(AFLAGS) $^ -o $@
clean:
        rm $(TARGET) $(OBJECTS)

src/hello.c:

Code:

#include <infinity/kernel.h>

int mod_init()
{
        printk(KERN_INFO «Hello, infinity kernel!n»);
        return 0;
}

int mod_uninit()
{
        printk(KERN_INFO «Goodbye infinity kernel :(n»);
        return 0;
}

error:

Code:

/tmp/ccdUfcT0.s: Assembler messages:
/tmp/ccdUfcT0.s:18: Error: invalid instruction suffix for `push’
/tmp/ccdUfcT0.s:44: Error: invalid instruction suffix for `push’
makefile:19: recipe for target ‘src/hello.o’ failed
make: *** [src/hello.o] Error 1

This is using the code from here, by the way (with some modifications to makefiles and other parts of the code unrelated to this), and I was able to compile the kernel as of last night… I’m now unable to compile both modules and the kernel but for simplicity I am just posting the test module:

https://github.com/GruntTheDivine/infin … ules/hello

Thanks very much, nv

Topic: Error: invalid instruction suffix for `push’  (Read 11421 times)

I tried to use one of the nightly builds, but now some of the programs I had written before no longer compile getting errors such as the thread subject.

Build log tags them as assembler messages.

Any advice on this would be appreciated.


Logged



Logged

(most of the time I ignore long posts)
[strangers don’t send me private messages, I’ll ignore them; post a topic in the forum, but first read the rules!]


Well, I checked the FAQ page already and there is nothing in it covering this problem.  There were also no other threads, I checked before I posted a new one.   — Turning on Full compiler logging just spits out the exact same messages.

C:UserscompAppDataLocalTemp/ccl1nhzH.s: Assembler messages:
C:UserscompAppDataLocalTemp/ccl1nhzH.s:485: Error: invalid instruction suffix for `push’
C:UserscompAppDataLocalTemp/ccl1nhzH.s:747: Error: invalid instruction suffix for `push’
C:UserscompAppDataLocalTemp/ccl1nhzH.s:749: Error: invalid instruction suffix for `push’
C:UserscompAppDataLocalTemp/ccl1nhzH.s:750: Error: invalid instruction suffix for `push’
C:UserscompAppDataLocalTemp/ccl1nhzH.s:751: Error: invalid instruction suffix for `push’
C:UserscompAppDataLocalTemp/ccl1nhzH.s:942: Error: invalid instruction suffix for `pop’

If no one has a clue, I will just download the original again, but I was hoping to not have to set it all back up again.  I assume I did something wrong in adding the nightly build.  I am reading now that the nightly was to be in a new folder and not meant to replace existing files?

« Last Edit: September 19, 2012, 06:40:51 am by Incantrix »


Logged


Turning on Full compiler logging just spits out the exact same messages.

(The messages would be the same regardless of the level of logging.)  What you posted is just the messages (the full log is under the «Build log» tab; not the «Build messages»).
Can you post your full log?


Logged


mingw32-g++.exe -Wall  -g    -I»C:Program Files (x86)CodeBlocksSDL-1.2.14include»  -c C:UserscompDesktopSourceLazyFooTwoCFile.cpp -o objDebugCFile.o
C:UserscompDesktopSourceLazyFooTwoCFile.cpp: In member function `void CFile::Render()’:
C:UserscompDesktopSourceLazyFooTwoCFile.cpp:248: warning: comparison between signed and unsigned integer expressions
C:UserscompAppDataLocalTemp/cc5Dk5yf.s: Assembler messages:
C:UserscompAppDataLocalTemp/cc5Dk5yf.s:485: Error: invalid instruction suffix for `push’
C:UserscompAppDataLocalTemp/cc5Dk5yf.s:747: Error: invalid instruction suffix for `push’

There are numerous repeats of the same error, with either ‘push’ or ‘pop’.


Logged


Unrelated to Code::Block, therefore locking the topic.

Please respect the forum rules you agreed to. Use the right forum (which is not the Code::Blocks forum) for these type of questions. We don’t provide compiler support here. Thank you.


Logged



Description


Ian Chivers



2011-04-21 15:29:20 UTC

I get the above error when trying to compile the following fortran module.

module timing_module
implicit none

integer , dimension(8) , private :: dt
real                   , private :: h,m,s,ms,tt
real                   , private :: last_tt

contains

subroutine start_timing()
implicit none
  call  date_and_time(values=dt)
  print 100 , dt(1:3),dt(5:8)
  100 format( 1x,i4,'/',i2,'/',i2,1x,i2,':',i2,':',i2,1x,i3)
  h  = real(dt(5))
  m  = real(dt(6))
  s  = real(dt(7))
  ms = real(dt(8))
  last_tt = 60*(60*h+m) + s + ms/1000.0
end subroutine start_timing

subroutine print_date_and_time
implicit none
  call  date_and_time(values=dt)
  print 100 , dt(1:3),dt(5:8)
  100 format( 1x,i4,'/',i2,'/',i2,1x,i2,':',i2,':',i2,1x,i3)
end subroutine print_date_and_time

subroutine print_hms
implicit none
  call  date_and_time(values=dt)
  print 100 , dt(5:8)
  100 format( 1x,i2,':',i2,':',i2,1x,i3)
end subroutine print_hms

subroutine print_ms
implicit none
  call  date_and_time(values=dt)
  h  = real(dt(5))
  m  = real(dt(6))
  s  = real(dt(7))
  ms = real(dt(8))
  tt = 60*(60*h+m) + s + ms/1000.0
  print 100 , tt
  100 format( 1x,f14.3)
end subroutine print_ms

subroutine print_time_difference
implicit none
  call  date_and_time(values=dt)
  h  = real(dt(5))
  m  = real(dt(6))
  s  = real(dt(7))
  ms = real(dt(8))
  tt = 60*(60*h+m) + s + ms/1000.0
  print 100 , (tt-last_tt)
  100 format( 1x,f14.3)
  last_tt=tt
end subroutine print_time_difference

real function time_difference()
implicit none
  tt      = 0.0
  call  date_and_time(values=dt)
  h  = real(dt(5))
  m  = real(dt(6))
  s  = real(dt(7))
  ms = real(dt(8))
  tt = 60*(60*h+m) + s + ms/1000.0
  time_difference=tt-last_tt
end function time_difference

end module timing_module 

Here is the output from gfortran -v

d:documentfortrannewbookexamplesch28gfortran>gfortran -v
Using built-in specs.
COLLECT_GCC=gfortran
COLLECT_LTO_WRAPPER=c:/program files (x86)/gfortran/bin/../libexec/gcc/i586-pc-m
ingw32/4.6.0/lto-wrapper.exe
Target: i586-pc-mingw32
Configured with: ../gcc-trunk/configure --prefix=/mingw --enable-languages=c,for
tran --with-gmp=/home/brad/gfortran/dependencies --disable-werror --enable-threa
ds --disable-nls --build=i586-pc-mingw32 --enable-libgomp --enable-shared --disa
ble-win32-registry --with-dwarf2 --disable-sjlj-exceptions --enable-lto
Thread model: win32
gcc version 4.6.0 20110214 (experimental) [trunk revision 170140] (GCC)

d:documentfortrannewbookexamplesch28gfortran>

This system is running Windows Vista Home Premium, 64 bit, sp2.


Comment 1


Ian Chivers



2011-04-21 15:44:07 UTC

I have just downloaded and installed the latest development version on this system and still get the same message. 

d:documentfortrannewbookexamplesch28gfortran>gfortran -v
Using built-in specs.
COLLECT_GCC=gfortran
COLLECT_LTO_WRAPPER=c:/program files (x86)/gfortran/bin/../libexec/gcc/i586-pc-m
ingw32/4.7.0/lto-wrapper.exe
Target: i586-pc-mingw32
Configured with: ../gcc-trunk/configure --prefix=/mingw --enable-languages=c,for
tran --with-gmp=/home/brad/gfortran/dependencies --disable-werror --enable-threa
ds --disable-nls --build=i586-pc-mingw32 --enable-libgomp --enable-shared --disa
ble-win32-registry --with-dwarf2 --disable-sjlj-exceptions --enable-lto
Thread model: win32
gcc version 4.7.0 20110419 (experimental) [trunk revision 170140] (GCC)

hope this helps.


Comment 2


kargl



2011-04-21 16:56:14 UTC

(In reply to comment #0)

> Target: i586-pc-mingw32


> This system is running Windows Vista Home Premium, 64 bit, sp2.

I think you may have the wrong version of gfortran.  You
are running a 64-bit OS but trying to use a 32-bit version
of the software.  I don't do Windows, but I suspect you
want the MinGW for Win64 from the gfortran wiki


Comment 3


Ian Chivers



2011-04-21 19:11:29 UTC

It was not clear to me which one I should have downloaded and installed.

I'm trying to finish a book for springer
and need most of the development stuff, including

  oop
  openmp
  mpi
  coarray

so assumed that 4.7.x was the one to download.

i've got a 32 bit windows system so i'll try 4.7.x
on that and let you know.

we try developing the examples for the book
on several systems and keeping track of them all
and the various compilers is a real headache.

hopefully this is just a 32/64 bit windows
problem from your point of view.

cheers

ian


Comment 4


Kai Tietz



2011-12-17 16:14:28 UTC

Yes, this issue happens if you are mixing 32-bit binutils and 64-bit gcc.  You can test, if you have actually downloaded an native 64-bit Windows gcc compiler, by specifying on command for compile only the option '-m32'.  I assume it will be successful then.
I've tested your module compilation by i686-w64-mingw32 fortran-compiler and it translates without flaws.


Comment 5


Andrew Pinski



2011-12-31 23:07:05 UTC

Not A GCC bug.

У меня были проблемы с компиляцией программы. Я не уверен, что это значит, и буду благодарен, если кто-нибудь сможет помочь.

C:UsersJoshuaDocumentsGitHubZeus-TSO_depslibmpg123dct64_sse.S: Assembler
messages:
C:UsersJoshuaDocumentsGitHubZeus-TSO_depslibmpg123dct64_sse.S:41: Error:
invalid instruction suffix for `push'
C:UsersJoshuaDocumentsGitHubZeus-TSO_depslibmpg123dct64_sse.S:46: Error:
invalid instruction suffix for `push'
C:UsersJoshuaDocumentsGitHubZeus-TSO_depslibmpg123dct64_sse.S:449: Error: invalid instruction suffix for `pop'
C:UsersJoshuaDocumentsGitHubZeus-TSO_depslibmpg123dct64_sse.S:451: Error: invalid instruction suffix for `pop'
_depslibmpg123CMakeFileslibmpg123_static.dirbuild.make:378: recipe for targe
t '_deps/libmpg123/CMakeFiles/libmpg123_static.dir/dct64_sse.S.obj' failed
mingw32-make[2]:  [_deps/libmpg123/CMakeFiles/libmpg123_static.dir/dct64_sse.
S.obj] Error 1
CMakeFilesMakefile2:225: recipe for target '_deps/libmpg123/CMakeFiles/libmpg12
3_static.dir/all' failed
mingw32-make[1]:  [_deps/libmpg123/CMakeFiles/libmpg123_static.dir/all] Error
2
Makefile:74: recipe for target 'all' failed
mingw32-make:  [all] Error 2

1

Решение

Похоже, что вы пытаетесь собрать 32-битный ассемблерный код с 64-битным ассемблером.

У вас есть 2 варианта:

  1. Используйте 32-битный ассемблер, например, используя --32 вариант;
  2. Изменить код путем замены 64-битных (расширенных) регистров, таких как %raxНапример, вместо 32-битных регистров, таких как %eax используется с push/pop инструкции.

Поскольку система сборки выглядит как CMake, я отсылаю вас к этому руководство о том, как настроить сборку для различных сборочных диалектов в CMake.

Вы можете попробовать:

set(CMAKE_ASM_FLAGS "--32")

но я не проверял это.

3

Другие решения

Других решений пока нет …

Неверный суффикс инструкции толкания при сборке с газом

При сборке файла на ассемблере GNU я получаю следующую ошибку:

hello.s: 6: Ошибка: неверный суффикс инструкции для `push ‘

Вот файл, который я пытаюсь собрать:

        .text
LC0:
        .ascii "Hello, world!12"
.globl _main
_main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        andl    $-16, %esp
        movl    $0, %eax
        movl    %eax, -4(%ebp)
        movl    -4(%ebp), %eax
        call    __alloca
        call    ___main
        movl    $LC0, (%esp)
        call    _printf
        movl    $0, %eax
        leave
        ret

Что здесь не так и как это исправить?

Проблема в некоторой степени связана с этот вопрос хотя ошибки и инструкции в вопросах разные.

64-битные инструкции

По умолчанию большинство операций остаются 32-битными, а 64-битные аналоги вызываются четвертым битом в префиксе REX. Это означает, что каждая 32-битная инструкция имеет естественное 64-битное расширение, а расширенные регистры бесплатны в 64-битных инструкциях.

movl $1,  %eax     # 32-bit instruction
movq $1,  %rax     # 64-bit instruction

pushl %eax         # Illegal instruction
pushq %rax         # 1 byte instruction encoded as pushl %eax in 32 bits
pushq %r10         # 2 byte instruction encoded as pushl preceeded by REX

Создан 23 июн.

Подготовить .code32 в качестве первой строки.

--32 опция изменит целевую платформу на 32-битную.

Создан 30 ноя.

Вы собираете на 64-битном ассемблере? Ваш код выглядит 32-битным. Я получаю эту ошибку с вашим кодом при использовании 64-битного ассемблера:

example.s:6:suffix or operands invalid for `push'

Но он отлично работает с 32-битным ассемблером.

Создан 07 июн.

Вы должны использовать «64-битный синтаксис», или вы можете использовать опцию «—32»: таким образом ассемблер переключает свою цель на платформу i386.

Создан 20 июля ’11, 12:07

Не тот ответ, который вы ищете? Просмотрите другие вопросы с метками

linux
compiler-errors
assembly
gnu-assembler

or задайте свой вопрос.

I am working my way through Professional Assembly Language by Richard Blum. Why? I like lower level programming and I find assembly language interesting.

My setup is a Mint Linux x64 box. Professional Assembly Language, and many of the other books on assembly language, tend to use i386 32-bit assembly. In fact there are more books on 32-bit assembly language on the market than there are on 64-bit assembly language. It is nice to learn by going through book examples, but I don’t want to have to change them too much. I don’t mind changing command line switches, but I don’t want to have to convert all code to 64-bit assembly while learning.

Trying to compile and link 32-bit assembly on an 64-bit machine, you can run into some issues. This post goes over how to get setup so you can assemble and link both 32-bit and 64-bit assembly on an x64 Linux machine.

You can compile assembly on Linux using just gcc. If you want to see how to do that, skip to the bottom of this post. Professional Assembly Language used the gnu assembler and linker, as and ld. My guess is for learning. The ability to see each step in the process is nice. We will use as and ld. To start, I am assembling and linking this program from the Chapter 04 of the book.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

# cpuid.s View the CPUID Vendor ID string using c library calls

.section .data

output:

    .asciz «The processor Vendor ID is ‘%s’n»

.section .bss

    .lcomm buffer, 12

.section .text

.globl _start

_start:

    movl $0, %eax

    cpuid

    movl $buffer, %edi

    movl %ebx, (%edi)

    movl %edx, 4(%edi)

    movl %ecx, 8(%edi)

    pushl $buffer

    pushl $output

    call printf

    addl $8, %esp

    pushl $0

    call exit

Using the as command to assemble.

as -o cpuid.o cpuid.s 
cpuid.s: Assembler messages:
cpuid.s:16: Error: invalid instruction suffix for 'push'
cpuid.s:17: Error: invalid instruction suffix for 'push'
cpuid.s:20: Error: invalid instruction suffix for 'push'

The first error I ran into says I have invalid instructions. That’s valid, I am trying to use 32-bit assembly instructions on a 64-bit machine. To fix that I had to tell the as command it to use 32-bit assembly. This is done by passing the --32 parameter.

as --32 -o cpuid.o cpuid.s

That worked and I got a cpuid.o 32-bit object code file in the directory. Next I try to link it using the ld command.

ld -o cpuid2 cpuid.o 
ld: i386 architecture of input file 'cpuid.o' is incompatible with i386:x86-64 output
cpuid.o: In function _start':
(.text+0x1f): undefined reference to 'printf'
cpuid.o: In function _start':
(.text+0x29): undefined reference to 'exit'

There are actually two errors here. The first is line one. The second is all the lines after. The first error is the `cpuid.o' is incompatible with i386 error. It is saying I assembled in 32-bit format but I am trying to link in 64-bit format. To fix that we tell the ld command to use a 32-bit architecture. This is done by passing the -m elf_i386 parameter. The -m parameter is the emulation linker. The man pages defines linker emulation as the “personality of the linker, which gives the linker default values for the other aspects of the target system” and specify that “the emulation can affect various aspects of linker behavior, particularly the default linker script”. I don’t know exactly what that means, but I think it means “act like a different architecture”.

ld -m elf_i386 -o cpuid2 cpuid.o

I run that and the first error has been fixed. We still get the second error.

cpuid.o: In function '_start':
(.text+0x1f): undefined reference to 'printf'
cpuid.o: In function '_start':
(.text+0x29): undefined reference to 'exit'

This is saying it can’t find printf or exit functions. Those functions are in libc. We need to tell the linker how to find them. The book uses dynamic linking with the --dynamic-linker command. In the book it looks like a single dash, but the man page for ld says it is a double dash --. Your linker location may be different. Mine was at /lib/ld-linux.so.2. It is possible to link statically instead of dynamically but we won’t cover that.

We add in the -lc to link libc into our program.

ld --dynamic-linker /lib/ld-linux.so.2 -m elf_i386 -o cpuid -lc cpuid.o

When I run that I get a different error. Here is where things start to get interesting.

ld: cannot find -lc

It can’t find libc.

Looking into the Linker

We can see where the linker is looking for libraries using the --verbose parameter. We keep all of our dynamic linker and 32-bit parameters.

ld --dynamic-linker /lib/ld-linux.so.2 -m elf_i386 -lc --verbose

That gives a lot of output. At the end of the output there is a section where it attempts to open various libc.so files.

attempt to open //usr/local/lib/i386-linux-gnu/libc.so failed
attempt to open //usr/local/lib/i386-linux-gnu/libc.a failed
attempt to open //lib/i386-linux-gnu/libc.so failed
attempt to open //lib/i386-linux-gnu/libc.a failed
attempt to open //usr/lib/i386-linux-gnu/libc.so failed
attempt to open //usr/lib/i386-linux-gnu/libc.a failed
attempt to open //usr/local/lib32/libc.so failed
attempt to open //usr/local/lib32/libc.a failed
attempt to open //lib32/libc.so failed
attempt to open //lib32/libc.a failed
attempt to open //usr/lib32/libc.so failed
attempt to open //usr/lib32/libc.a failed
attempt to open //usr/local/lib/libc.so failed
attempt to open //usr/local/lib/libc.a failed
attempt to open //lib/libc.so failed
attempt to open //lib/libc.a failed
attempt to open //usr/lib/libc.so failed
attempt to open //usr/lib/libc.a failed
attempt to open //usr/i386-linux-gnu/lib32/libc.so failed
attempt to open //usr/i386-linux-gnu/lib32/libc.a failed
attempt to open //usr/x86_64-linux-gnu/lib32/libc.so failed
attempt to open //usr/x86_64-linux-gnu/lib32/libc.a failed
attempt to open //usr/i386-linux-gnu/lib/libc.so failed
attempt to open //usr/i386-linux-gnu/lib/libc.a failed
ld: cannot find -lc

All of its attempts failed.

Packages

At this point I am thinking “Maybe I don’t have the 32-bit libc on the box. I read some tutorials. There are various suggestions on adding in multiple architectures. I try some different commands. None help. It looks like I have all the packages and libraries installed already.

sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get dist-upgrade
sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386
sudo apt-get install multiarch-support

Then this stack overflow post recommended installing g++ multiarch. Looks like I didn’t have that installed after all.

sudo apt-get install gcc-multilib g++-multilib

That installs a bunch of packages. The important one which installs a 32-bit libc is libc6-dev-i386. A lot of the packages look related to i386 32-bit development.

The following additional packages will be installed:
  g++-5-multilib gcc-5-multilib lib32asan2 lib32atomic1 lib32cilkrts5 lib32gcc-5-dev lib32gomp1 lib32itm1 lib32mpx0 lib32quadmath0 lib32stdc++-5-dev
  lib32ubsan0 libc6-dev-i386 libc6-dev-x32 libc6-x32 libx32asan2 libx32atomic1 libx32cilkrts5 libx32gcc-5-dev libx32gcc1 libx32gomp1 libx32itm1
  libx32quadmath0 libx32stdc++-5-dev libx32stdc++6 libx32ubsan0

When the install is done.

attempt to open //usr/local/lib/i386-linux-gnu/libc.so failed
attempt to open //usr/local/lib/i386-linux-gnu/libc.a failed
attempt to open //lib/i386-linux-gnu/libc.so failed
attempt to open //lib/i386-linux-gnu/libc.a failed
attempt to open //usr/lib/i386-linux-gnu/libc.so failed
attempt to open //usr/lib/i386-linux-gnu/libc.a failed
attempt to open //usr/local/lib32/libc.so failed
attempt to open //usr/local/lib32/libc.a failed
attempt to open //lib32/libc.so failed
attempt to open //lib32/libc.a failed
attempt to open //usr/lib32/libc.so succeeded
opened script file //usr/lib32/libc.so
opened script file //usr/lib32/libc.so
attempt to open /lib32/libc.so.6 succeeded
/lib32/libc.so.6
attempt to open /usr/lib32/libc_nonshared.a succeeded
attempt to open /lib32/ld-linux.so.2 succeeded
/lib32/ld-linux.so.2
/lib32/ld-linux.so.2
ld-linux.so.2 needed by /lib32/libc.so.6
found ld-linux.so.2 at /lib32/ld-linux.so.2

The linker is now able to find libc under /lib32/libc.so.6 Another piece that is interesting is the output format and architecture at the top of the ld output.

OUTPUT_FORMAT("elf32-i386", "elf32-i386",
	      "elf32-i386")
OUTPUT_ARCH(i386)

This shows that we are linking a 32-bit elf executable.

Linking

With the linker being able to find our 32-bit libc we can now go back to our ld command.

ld --dynamic-linker /lib/ld-linux.so.2 -m elf_i386 -o cpuid -lc cpuid.o
./cpuid

The linker works. It finds libc and creates an executable from our 32-bit assembly code. Running that we get the output below.

The processor Vendor ID is 'GenuineIntel'

Summary

I took the round about way to show a train of thought and maybe give some insight into how all parts are working when trying assemble and link 32-bit assembly on an x64 machine. In short, if you want to assemble and link 32-bit assembly on an x64 machine make sure your computer is configured correctly for multi-architecture. Install all of the following packages if they aren’t already installed.

sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get dist-upgrade
sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386
sudo apt-get install multiarch-support
sudo apt-get install gcc-multilib g++-multilib

When assembling using the --32 parameter. When linking use the -m elf_i386 parameter. The entire flow looks like this.

as --32 -o cpuid.o cpuid.s
ld --dynamic-linker /lib/ld-linux.so.2 -m elf_i386 -o cpuid -lc cpuid.o
./cpuid

If you use the file command on the cpuid executable you will see we have assembled, linked, and executed a 32-bit assembly on a 64-bit machine.

file cpuid
cpuid: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, not stripped

x64 Assembly Language

Can we still assemble x64 on the same machine? Yes. Easily. I took a hello world x64 example I found, saved it as hello.s assembled it, linked it, and executed it.

as -o hello.o hello.s
ld -o hello hello.o
./hello

Using the file command again, we see we have assembled, linked, and executed a 64-bit elf executable.

file cpuid
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped

Using GCC instead

Instead of using as and ld, we can use gcc to handle both stages. We still need to have our environment setup correctly as with as and ld. We also need to change our assembly source code globl label from _start to main.

We use the -m32 parameter with gcc to assemble and link in 32-bit format in one step.

gcc -m32 cpuid.s -o cpuid
./cpuid
The processor Vendor ID is 'GenuineIntel'
file cpuid
cpuid: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, ...

And that’s it. One machine, both 32-bit and 64-bit assembly.



Понравилась статья? Поделить с друзьями:
  • Error invalid input syntax for type double precision
  • Error invalid input range
  • Error invalid icon file
  • Error invalid hwid neverlose
  • Error invalid glob argument undefined